Performante Array iteration

  • Themenstarter Themenstarter Guest
  • Beginndatum Beginndatum
Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Hallo

Mich würde interessieren ob das

Code:
for(String name : strArray)
{
			
}

genauso performant ist wie das

Code:
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!
 
Code:
int count = 0;
      
while(true)
{
          try
          {
             array[count];
          }
          catch(ArrayIndexOutOfBoundsException aex)
          {
             
          }
}

Das ist totaler Blödsinn. Wo hast du das her?
 
Oha wenn ich schon
Code:
while(true)
mit ner Exception als "Abbruchbedingung" sehe bekomme ich schon Kopfschmerzen. Wer kommt denn immer auf solche merkwürdigen Ideen?
 
geht schneller als

Code:
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
 
der count = 0 sollte natürlich incrementiert werden hab ich vergessen
 
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?
 
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.
 
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.
 
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?
 
Anonymous hat gesagt.:
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?

:?:
Nein, die Schleife läuft bis array.length. Was denkst du denn?
 
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.
 
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.
 
tfa hat gesagt.:
Anonymous hat gesagt.:
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?

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

Wie meinst du findet er herraus wann er array.length erreicht hat? Vielleicht durch einen Vergleich?
 
Kann es sein das das Exception-Objekt weg optimiert wird da ich es in dieser Variante garnicht verwende?
 
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?
 
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?
 
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.
 
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.
 
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?

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?


😀 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 ? 😀
 
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:

Code:
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.
 
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:

Code:
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:
Code:
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
 
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:

Code:
private static final int[] a = new int[100000000];
 
Ach so... ja, 100 Millionen ints, nicht 100 Millionen Byte 🙂 Also dann 400 MB.
 
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.
 
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 😉
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben