2014-08-28 3 views
5

ich in der RegelWie Java schreiben für Schleifen wiederholt zu vermeiden, dass die obere Berechnung gebundenen

for (int i = 0, n = someMethod(); i < n; i++) 

in Vorzug

for (int i = 0; i < someMethod(); i++) 

schreiben zu vermeiden someMethod() wiederholt berechnet wird. Aber ich bin mir nie wirklich sicher, wann ich das tun muss. Wie schlau ist es, dass Java Methoden erkennt, die jedes Mal das gleiche Ergebnis liefern und nur einmal am Anfang einer Schleife ausgeführt werden müssen?

+0

Warum können Sie nicht tun wie 'int n = someMethod(); ' und dann n später in der Schleife? – Adi

+1

Ich denke, dass http://StackOverflow.com/questions/6093537/for-loop-optimization diese Frage beantwortet. – trooper

+0

Adi, das habe ich in meinem ersten Beispiel gemacht. Meine Frage ist wann ist es notwendig, n zuerst zu berechnen. Ich bin mir sicher, dass es einige Fälle gibt, in denen die zweite Art, wie ich sie geschrieben habe, sowieso wie die erste behandelt wird, aber ich könnte mich damit irren. –

Antwort

1

Das JIT wird, soweit ich das beurteilen kann, dies nur erkennen, wenn es sich um eine relativ einfache Inline-Methode handelt. Davon abgesehen ist es sehr einfach für einen Programmierer, diese Fälle zu erkennen, und es ist ein schweres Problem für einen JIT-Compiler zu erkennen. Vorzugsweise sollten Sie final int verwenden, um Ergebnisse von großen Methoden zwischenzuspeichern, da der JIT sehr leicht erkennen kann, dass sich der Wert nicht ändern kann, und sogar Array-Zugriffsprüfungen zur Beschleunigung von Schleifen entfernen kann.

So etwas wie

int[] arr = new int[ 10 ]; 
for(int i = 0; i < arr.length; i++) { 
    //... 
} 

oder

List<String> list = Arrays.asList(new String[] { ... }); 
for(int i = 0; i < list.size(); i++) { 
    //... 
} 

wahrscheinlich sehr leicht durch den JIT optimiert werden kann. Andere Loops, die große oder komplizierte Methoden aufrufen, können nicht ohne weiteres den gleichen Wert zurückgeben, aber Methoden wie size() könnten wahrscheinlich inline oder sogar vollständig entfernt werden.

Schließlich mit for-jeder Schleifen auf Arrays. Sie sind zu der ersten Schleife verfallen, die ich im Fall von Arrays geschrieben habe, und können auch leicht optimiert werden, um die schnellste Schleife zu erzeugen. Obwohl for-each auf Nicht-Arrays schleift, bevorzuge ich es, wenn es um schnelle Schleifen geht, da diese in Iterator-Schleifen zerfallen und nicht die zweite Schleife, die ich gepostet habe. Dies gilt nicht für LinkedList, da ein Iterator schneller ist als get() aufgrund von O (n) traversal.

Dies ist alles Spekulation darüber, was das JIT tun könnte, um eine Schleife zu optimieren. Es ist wichtig zu wissen, dass das JIT nur etwas optimiert, das die resultierenden Effekte nicht verändern kann. Die Dinge einfach zu halten, wird die Arbeit des JITs viel einfacher machen. Wie mit dem endgültigen Keyword. Die Verwendung von finalen Werten oder Methoden ermöglicht es dem JIT, leicht zu beweisen, dass sich nichts ändert und inline wie verrückt werden kann. Das ist die wichtigste Optimierung des JIT, Inlining. Machen Sie diesen Job einfach und das JIT hilft Ihnen im großen Stil.

Hier ist eine link Diskussion Schleife Optimierungen, wo das JIT kann nicht immer eine Schleife optimieren, wenn es nicht beweisen kann, dass die Optimierung nichts ändert.

+0

Danke, das ist eine sehr gründliche Antwort. Ich wäre wirklich interessiert zu wissen, ob es andere gängige Methoden abgesehen von der Größe() gibt, die auf diese Weise inline werden. In Ihrem zweiten Beispiel, wenn die erste Zeile war Liste list = Arrays.asList (arr); Stattdessen könnte sich die Größe() in der Schleife ändern. Wäre der JIT in der Lage zu erkennen, wenn arr nicht in der Schleife und Inline-Größe() in diesem Fall geändert wird? –

+0

@PaulBoddington Technisch arr.length könnte sich jederzeit auch ändern. Seit List.get() und List.size() auf ArrayList sind im Grunde nur Wrapper um einen einzigen Array-Zugriff. Ich würde annehmen, dass sobald es inline ist, es sehr wie die erste Schleife aussehen wird. Das könnte gerade genug sein, damit das JIT es weiter optimieren kann. –

+0

@PaulBoddington Ich denke mehr, was ich hier zu sagen versuche, ist, dass das JIT viel besser in Inlining ist. Das ist seine primäre Optimierung. Es geht in Bewegung, und es ist sehr effektiv. Das Erkennen von sich nicht ändernden Werten, wenn es sich um Schleifen handelt, ist vor allem nützlich, um Überprüfungen außerhalb der Grenzen zu entfernen. Dies ist wahrscheinlich die zweitgünstigste Optimierung, die das JIT durchführen kann. –

4

Ich glaube, es liegt an Ihnen, als Programmierer, Fälle zu identifizieren, in denen die Obergrenze Ihrer for-loop im laufenden Betrieb berechnet werden muss und sie entsprechend zu adressieren.

Unter der Annahme, dass der Wert von n nicht auf irgendeine Operation abhängt, die innerhalb der Schleife ausgeführt wird, persönlich, würde ich es als

geschrieben bevorzugen
int n = someMethod(); 
for (int i = 0; i < n; i++); 

, weil es die häufigste Art von for-loop bewahrt, während eindeutig definiert, die obere Grenze.

+2

Ich stimme zu, dass die Last auf mich ist. Ich habe nur aus akademischem Interesse nachgefragt; Ich berechne immer zuerst n. Ich würde es immer noch vorziehen, es wie in meinem ersten Beispiel zu schreiben, um den Umfang von n auf die Schleife zu beschränken. –

+0

@Paul Völlig verständlich. Hinsichtlich des Umfangs: Dies ist situativ für mich, aber die verbesserte Lesbarkeit gewinnt normalerweise. – voidHead

Verwandte Themen