Frage

Gibt es einen Unterschied in der Leistung zwischen dem for-Schleifen auf einem primitiven Array?

Angenommen:

double[] doubleArray = new double[300000];


for (double var: doubleArray) 
   someComplexCalculation(var);

oder:

for ( int i = 0, y = doubleArray.length; i < y; i++)
   someComplexCalculation(doubleArray[i]);

Tester

Ich profilierte es tatsächlich:

Total timeused for modern loop= 13269ms
Total timeused for old loop   = 15370ms

So ist die moderne Schleife tatsächlich schneller läuft, zumindest auf meinem Mac OSX JVM 1.5.

War es hilfreich?

Lösung

Ihre handgeschriebene, „alte“ Form weniger Befehle ausführt, und kann schneller sein, obwohl Sie es unter einem bestimmten JIT-Compiler profilieren müssten sicher zu wissen. Die "neue" Form ist auf jeden Fall nicht schneller.

Wenn Sie an dem demontierten Code aussehen (zusammengestellt von Suns JDK 1.5), werden Sie sehen, dass die „neue“ Form wie den folgenden Code entspricht:

1: double[] tmp = doubleArray;
2: for (int i = 0, y = tmp.length; i < y; i++) {
3:   double var = tmp[i];
4:   someComplexCalculation(var);
5: }

So können Sie sehen, dass mehr lokale Variablen verwendet werden. Die Zuordnung von doubleArray an der Linie tmp 1 „extra“, aber es tritt nicht in der Schleife, und wahrscheinlich nicht gemessen werden kann. Die Zuordnung in Zeile var 3 ist ebenfalls Extra. Wenn es ein Unterschied in der Leistung ist, würde dies verantwortlich sein.

Zeile 1 könnte unnötig erscheinen, aber es ist vorformulierten das Ergebnis zwischenzuspeichern, wenn das Array mit einem Verfahren vor dem Eintritt in die Schleife berechnet wird.

Das heißt, würde ich das neue Formular verwenden, wenn Sie etwas mit den Index-Variablen tun müssen. Jeder Performance-Unterschied ist wahrscheinlich durch die JIT-Compiler zur Laufzeit optimiert werden entfernt, und die neue Form ist klar. Wenn Sie weiterhin, es zu tun „von Hand“, können Sie über die künftigen Optimierungen verpassen. Im Allgemeinen kann ein guter Compiler „dumm“ Code gut optimieren, aber stolpert über „intelligenten“ Code.

Andere Tipps

Meine Meinung ist, dass Sie nicht wissen, und sollte nicht erraten. Der Versuch, Compiler in diesen Tagen auszutricksen ist fruchtlos.

Es gab Zeiten Menschen gelernt „Patterns“, die eine Operation zu optimieren schien, aber in der nächsten Version von Java diese Muster waren tatsächlich langsamer.

Schreiben Sie immer es so klar, wie es Ihnen möglich ist und sich keine Sorgen über die Optimierung bis Sie tatsächlich einige Benutzer spec in der Hand haben und versagen einige Anforderung gerecht zu werden, und selbst dann sehr vorsichtig sein, bevor laufen und nach Tests sicherzustellen, dass Ihre „fix“ verbessert es tatsächlich genug, diese Anforderung weiter zu machen.

Der Compiler kann einige erstaunliche Dinge tun, die wirklich Ihre Socken weg blasen würde, und selbst wenn Sie einige Test machen, dass iteriert über einige große Reichweite, ist es völlig anders verhalten können, wenn Sie einen kleineren Bereich oder ändern, was in der Schleife passiert .

Just in time bedeutet Compilieren kann es gelegentlich zu übertreffen C, und es gibt keinen Grund, es nicht statisch Assemblersprache in einigen Fällen übertreffen können (Assembly nicht bestimmen kann vorher, dass ein Anruf nicht erforderlich ist, Java kann manchmal tun dass nur.

Um es zusammenzufassen:. Die meisten Wert, den Sie in Ihren Code setzen kann, ist, es zu schreiben lesbar sein

Warum messen Sie es nicht selbst?

Das klingt ein bisschen hart, aber diese Art von Fragen sind sehr einfach, sich selbst zu überprüfen.

Just das Array und jede Schleife 1000 oder mehr Male ausgeführt werden, und die Menge an Zeit messen. Wiederholen Sie mehrmals Störungen zu beseitigen.

Es gibt keinen Unterschied. Java wird die erweiterte für in den normalen for-Schleife verwandeln. Die erhöhte für nur eine „Syntax Zucker“. Der Bytecode erzeugt wird, ist das gleiche für beide Schleifen.

Ich habe sehr neugierig auf Ihre Frage, auch nach meiner vorherigen Antwort. Also habe ich beschlossen, es selbst zu überprüfen. Ich schrieb dieses kleine Stück Code (bitte math Korrektheit über die Überprüfung ignorieren, wenn eine Zahl prim ist; -)):

public class TestEnhancedFor {

    public static void main(String args[]){
        new TestEnhancedFor();
    }

    public TestEnhancedFor(){
        int numberOfItems = 100000;
        double[] items = getArrayOfItems(numberOfItems);
        int repetitions = 0;
        long start, end;

        do {
            start = System.currentTimeMillis();
            doNormalFor(items);
            end = System.currentTimeMillis();
            System.out.printf("Normal For. Repetition %d: %d\n", 
                    repetitions, end-start);

            start = System.currentTimeMillis();
            doEnhancedFor(items);
            end = System.currentTimeMillis();
            System.out.printf("Enhanced For. Repetition %d: %d\n\n", 
                    repetitions, end-start);

        } while (++repetitions < 5);
    }

    private double[] getArrayOfItems(int numberOfItems){
        double[] items = new double[numberOfItems];
        for (int i=0; i < numberOfItems; i++)
            items[i] = i;
        return items;
    }

    private void doSomeComplexCalculation(double item){
        // check if item is prime number
        for (int i = 3; i < item / 2; i+=2){
            if ((item / i) == (int) (item / i)) break;
        }
    }

    private void doNormalFor(double[] items){
        for (int i = 0; i < items.length; i++)
            doSomeComplexCalculation(items[i]);
    }

    private void doEnhancedFor(double[] items){
        for (double item : items)
            doSomeComplexCalculation(item);
    }

}

Ausführen der App ergab die folgenden Ergebnisse für mich:

  

Normal Für ein. Wiederholung 0: 5594   Verbesserte Für. Wiederholung 0: 5594

     

Normal Für ein. Wiederholung 1: 5531   Verbesserte Für. Wiederholung 1: 5547

     

Normal Für ein. Wiederholung 2: 5532   Verbesserte Für. Wiederholung 2: 5578

     

Normal Für ein. Wiederholung 3: 5531   Verbesserte Für. Wiederholung 3: 5531

     

Normal Für ein. Wiederholung 4: 5547   Verbesserte Für. Wiederholung 4: 5532

Wie wir sehen können, die Unterschiede zwischen den Ergebnissen sind sehr klein, und manchmal die normale Schleife schneller ausgeführt wird, manchmal die erweiterte Schleife schneller ist. Da es andere Anwendungen in meinem Computer geöffnet sind, finde ich es normal. Außerdem wird nur die erste Ausführung ist langsamer als die andere -. Ich glaube, das mit JIT-Optimierungen zu tun hat

Durchschnittszeiten (mit Ausnahme der ersten Wiederholung) sind für die normale 5535,25ms Schleife und 5547ms für die erweiterte Schleife. Aber wir können sehen, dass die besten Laufzeiten für beide Schleifen gleich ist (5531ms), also denke ich, dass wir zu dem Schluss kommen können, dass beide Schleifen die gleiche Leistung haben - und die Schwankungen der verstrichenen Zeit sind aufgrund anderer Anwendungen (auch das Betriebssystem) der Maschine.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top