# Performante Array iteration



## Guest (8. Mai 2008)

Hallo

Mich würde interessieren ob das


```
for(String name : strArray)
{
			
}
```

genauso performant ist wie das


```
int count = 0;
		
while(true)
{
		    try
		    {
		    	array[count];
		    }
		    catch(ArrayIndexOutOfBoundsException aex)
		    {
		    	
		    }
}
```

Hat jemand Hintergrundwissen über die Optimierung der verkürzten For-Schleife oder Literatur zu dem Thema?

peace!


----------



## Wildcard (8. Mai 2008)

```
int count = 0;
      
while(true)
{
          try
          {
             array[count];
          }
          catch(ArrayIndexOutOfBoundsException aex)
          {
             
          }
}
```

Das ist totaler Blödsinn. Wo hast du das her?


----------



## ARadauer (8. Mai 2008)

nicht alles was funktioniert, ist sinnvoll


----------



## Gast (8. Mai 2008)

Oha wenn ich schon

```
while(true)
```
mit ner Exception als "Abbruchbedingung" sehe bekomme ich schon Kopfschmerzen. Wer kommt denn immer auf solche merkwürdigen Ideen?


----------



## Guest (8. Mai 2008)

geht schneller als


```
for(int index = 0; index < array.size(); index++)
{
     array[index];
}
```

weil da zweimal verglichen wird, einmal durch die For-Schleife und einmal "Array intern", also spart man sich einen Vergleich.

Deshalb die Frage ob bzw. wie die verkürzte For-Schleife optimiert wird.


peace


----------



## Guest (8. Mai 2008)

der count = 0 sollte natürlich incrementiert werden hab ich vergessen


----------



## foobar (8. Mai 2008)

> weil da zweimal verglichen wird, einmal durch die For-Schleife und einmal "Array intern", also spart man sich einen Vergleich.
> Deshalb die Frage ob bzw. wie die verkürzte For-Schleife optimiert wird.


Hast du dir das ausgedacht?
Diese "Optimierung" bringt dir bei 10 Million Iterationen vielleicht eine Performancesteiergung von 5 Millis, dafür haste aber nen absolut kruden Code und jeder andere Entwickler wird fragen WTF?


----------



## tfa (8. Mai 2008)

Ich würde sagen, dass die zweite Lösung sogar langsamer ist als die vernünftige foreach-Schleife. Denn hier könnte der JIT den Array-Bound-Check weg optimieren. Von der Code-Qualität ganz zu schweigen.


----------



## AlArenal (8. Mai 2008)

If it ain't broke, don't fix it. Hätte man es tatsächlich nötig sich über dererlei Mikrooptimierungen Gedanken zu machen, hätte man besser nicht zu Java gegriffen, sondern gleich in C, Fortran oder Assembler programmiert.


----------



## Guest (8. Mai 2008)

tfa hat gesagt.:
			
		

> Ich würde sagen, dass die zweite Lösung sogar langsamer ist als die vernünftige foreach-Schleife. Denn hier könnte der JIT den Array-Bound-Check weg optimieren. Von der Code-Qualität ganz zu schweigen.



Achja und wie bitte schaut dann der Maschinencode aus? läuft er einfach durch den Hauptspeicher wie er lustig ist und hört dann per Zufall an einer Stelle auf?


----------



## tfa (8. Mai 2008)

Anonymous hat gesagt.:
			
		

> tfa hat gesagt.:
> 
> 
> 
> ...



 :?: 
Nein, die Schleife läuft bis array.length. Was denkst du denn?


----------



## Wildcard (8. Mai 2008)

Anonymous hat gesagt.:
			
		

> Achja und wie bitte schaut dann der Maschinencode aus? läuft er einfach durch den Hauptspeicher wie er lustig ist und hört dann per Zufall an einer Stelle auf?


Der JIT kann das Bounds Checking wegoptimieren, nicht das Checking ob noch ein Schleifendurchlauf kommt.
Deine 'Variante' dürfte mit ziemlicher Sicherheit langsamer sein wegen besagtem Boundschecking und auch weil es sehr teuer sein kann ein Exception Objekt zu erzeugen.
Selbst wenn es nicht langsamer wäre, sowas macht man nicht. Niemals.


----------



## tfa (8. Mai 2008)

Eine Exception zu erzeugen ist auf jeden Fall teuer, da ein Stacktrace generiert werden muss. Keine Ahnung, wie viele 1000 Boundchecks man in der Zeit machen kann.


----------



## Guest (8. Mai 2008)

tfa hat gesagt.:
			
		

> Anonymous hat gesagt.:
> 
> 
> 
> ...



Wie meinst du findet er herraus wann er array.length erreicht hat? Vielleicht durch einen Vergleich?


----------



## Guest (8. Mai 2008)

Kann es sein das das Exception-Objekt weg optimiert wird da ich es in dieser Variante garnicht verwende?


----------



## tfa (8. Mai 2008)

Anonymous hat gesagt.:
			
		

> Wie meinst du findet er herraus wann er array.length erreicht hat? Vielleicht durch einen Vergleich?


Wie glaubst du, findet er heraus, ob eine ArrayIndexOutOfBoundsException geworfen werden muss?


----------



## Gast (8. Mai 2008)

Oh man nur weil die Schleife so funktioniert ist es noch lange keine gute Schleife. Eine Exception ist nicht dazu gedacht irgendwelche Schleifen abzubrechen wenn man am Ende ist. Eine Exception dient dazu einen Fehler bekannt zu machen (und evtl. zu behandeln).
Beispiel aus dem alltäglichen Leben:

Stell dir vor du fährst mit einem Auto nach hause und willst dann in der Garage parken. Was machst du?

1. Einfach mit Vollgas rein weil das Auto nachdem es die Wand trifft eh stehen bleibt?

oder

2. Schauen wie viel Platz noch ist um dann vor einer Kollision mit der Wand anzuhalten?


----------



## Guest (8. Mai 2008)

tfa hat gesagt.:
			
		

> Ich würde sagen, dass die zweite Lösung sogar langsamer ist als die vernünftige foreach-Schleife. Denn hier könnte der JIT den Array-Bound-Check weg optimieren. Von der Code-Qualität ganz zu schweigen.



Sorry, jetzt hab ich dich verstanden  :shock: 
Ich würde mir da aber gerne sicher sein, was beide Beispiele betrifft.


----------



## Wildcard (8. Mai 2008)

> Ich würde mir da aber gerne sicher sein, was beide Beispiele betrifft.


Unnötig. Deine Variante kommt keinesfalls in Frage.
Um 'Optimierungen' sollte man sich sowieso erst dann kümmern, wenn man ein Performanceproblem hat. Wenn man anfängt, dann auch nicht blindlings drauf los, sondern anhand einer Profiler Analyse.
Glaub mir, der Bottleneck ist (sofern du einen hast) nicht die Foreachschleife.


----------



## Guest (8. Mai 2008)

Gast hat gesagt.:
			
		

> Oh man nur weil die Schleife so funktioniert ist es noch lange keine gute Schleife. Eine Exception ist nicht dazu gedacht irgendwelche Schleifen abzubrechen wenn man am Ende ist. Eine Exception dient dazu einen Fehler bekannt zu machen (und evtl. zu behandeln).
> Beispiel aus dem alltäglichen Leben:
> 
> Stell dir vor du fährst mit einem Auto nach hause und willst dann in der Garage parken. Was machst du?
> ...




  Lustiger Vergleich aber leider falsch

Das Auto bremst in dem Fall von allein und kommt nicht zu schaden, ich laufe ja nicht aus dem Speicherbereich herraus sondern nur bis zu dessen Ende also mache ich auch nichts kaputt

----

Hier hat nicht zufällig jemand lust sich das ganze mal deassimbliert anzuschauen und hier zu posten ?


----------



## Gast (8. Mai 2008)

Ne, der try..catch block bleibt erhalten. Ne ArrayIndexOutOfBounds Exception ist eine RuntimeException, diese muss von der methode, die sie wirft nicht explizit angegeben werden. mit anderen worten: soetwas funktioniert: 


```
public double squareRoot(double value) {
 if(value < 0) 
   throw new IllegalArgumentException("Wurzel kann nur von Positiven zahlen gezogen werden"); 
 return Math.sqrt(value); 

}
```

Außerdem habe ich an mehreren stellen gelesen, dass try..catch blöcke sehr unperformant sind, da zusätzlich zur normalen abarbeitung des codes auch noch überwacht werden muss, ob eine exception geworfen wird, und wer sie auffängt. Das kostet definitiv mehr zeit, als das iterieren mittels for Schleife.


----------



## Guest (9. Mai 2008)

Anonymous hat gesagt.:
			
		

> Hier hat nicht zufällig jemand lust sich das ganze mal deassimbliert anzuschauen und hier zu posten ?


Nö, aber man kann das ganze ja einfach mal mit einem großen Array (100MB) messen:


```
public class Autsch
{
	private static final int[] a = new int[100000000];

	private static void test1()
	{
		Benchmark bm = new Benchmark("klassisch");
		int s = 0;
		bm.start();
		for (int x: a)
		{
			s += x;
		}
		bm.stop();
	}

	private static void test2()
	{
		Benchmark bm = new Benchmark("Exception");
		int s = 0;
		bm.start();
		int i = 0;
		try
		{
			while (true)
			{
				s += a[i++];
			}
		}
		catch (ArrayIndexOutOfBoundsException e)
		{
		}
		bm.stop();
	}

	public static void main(String[] args)
	{
		for (int i = 0; i < 10; ++i)
		{
			test1();
			test2();
		}
	}
}
```

Bei 10 Messungen bekomme ich folgendes Ergebnis heraus:

```
klassisch: 187 ms
Exception: 236 ms
klassisch: 187 ms
Exception: 234 ms
klassisch: 147 ms
Exception: 234 ms
klassisch: 146 ms
Exception: 234 ms
klassisch: 147 ms
Exception: 236 ms
klassisch: 145 ms
Exception: 235 ms
klassisch: 146 ms
Exception: 234 ms
klassisch: 146 ms
Exception: 234 ms
klassisch: 146 ms
Exception: 236 ms
klassisch: 148 ms
Exception: 235 ms
```

Die Exception-Variante ist also deutlich teurer.

Fred


----------



## AlArenal (9. Mai 2008)

Liebling, ich habe die Integer geschrumpft!



			
				Fred hat gesagt.:
			
		

> Nö, aber man kann das ganze ja einfach mal mit einem großen Array (100MB) messen:
> 
> 
> ```
> ...


----------



## Guest (9. Mai 2008)

AlArenal hat gesagt.:
			
		

> Liebling, ich habe die Integer geschrumpft!


Und was willst Du mir mit diesem Posting sagen?


----------



## Guest (9. Mai 2008)

Ach so... ja, 100 Millionen ints, nicht 100 Millionen Byte  Also dann 400 MB.


----------



## AlArenal (9. Mai 2008)

;-)


----------



## Marco13 (9. Mai 2008)

Interessanterweise ist der Unterschied zwischen "for" und "exception" ziemlich stark davon abhängig, ob der array _final_ ist oder nicht. Da optimiert der JIT anscheinend noch ein bißchen...

EDIT: Bei mir ist der Unterschied übrigens etwas geringer ... man sollte ggf. noch die JVM-Version angeben. Aber besonders repräsentativ ist der Micro-Benchmark eh nicht.


----------



## Janus (12. Mai 2008)

wie wird der compiler wohl die aufgabe lösen, eine out of bounds exception zu überprüfen? er weiss ganz genau, wie groß das array ist, also wird er exakt so, wie es für die for-schleife nötig ist, bei jedem aufruf des array indices die werte vergleichen. hinzu kommt bei der exception variante aber noch der ganze overhead, der für abfangen von exceptions nötig ist. die variante kann einfach nicht schneller sein.
übrigens kommt diese "exotische" variante in einigen büchern zum thema falsche optimierung vor


----------

