Hüten Sie sich vor den Gefahren des Micro-Benchmarking!!!
Ich nahm den Code, wickelte eine Methode um die Außenseite, und führte das 10 Mal in einer Schleife. Ergebnisse:
50, 3,
3, 0,
0, 0,
0, 0,
....
Ohne tatsächlichen Code in den Schleifen sind die Compiler in der Lage, herauszufinden, dass die Schleifen keine nützliche Arbeit leisten, und sie vollständig zu optimieren. In Anbetracht der gemessenen Leistung vermute ich, dass diese Optimierung möglicherweise von javac
.
Lektion 1: Compiler optimieren oft Code weg, der nutzlose "Arbeit" macht. Je intelligenter der Compiler ist, desto wahrscheinlicher ist es, dass so etwas passiert. Wenn Sie dies bei der Programmierung nicht berücksichtigen, kann ein Benchmark bedeutungslos sein.
Also habe ich die folgende einfache Berechnung in beide Schleifen eingefügt if (i < 2 * j) longK++;
und ließ die Testmethode den endgültigen Wert von longK
. Ergebnisse:
32267, 33382,
34542, 30136,
12893, 12900,
12897, 12889,
12904, 12891,
12880, 12891,
....
Wir haben offensichtlich verhindert, dass die Compiler die Schleife wegoptimieren. Aber jetzt sehen wir die Auswirkungen des JVM-Warmups in (in diesem Fall) den ersten beiden Paaren von Schleifeniterationen. Die ersten beiden Iterationspaare (ein Methodenaufruf) werden wahrscheinlich im reinen Interpretationsmodus ausgeführt. Und es sieht so aus, als würde die dritte Iteration tatsächlich parallel zum JIT laufen. Beim dritten Iterationspaar handelt es sich höchstwahrscheinlich um reinen nativen Code. Und von da an ist der Unterschied zwischen dem Timing der beiden Schleifenversionen nur noch Rauschen.
Lektion 2: Berücksichtigen Sie immer die Auswirkungen der JVM-Aufwärmphase. Dies kann die Benchmark-Ergebnisse sowohl auf der Mikro- als auch auf der Makroebene erheblich verzerren.
Fazit: Sobald die JVM aufgewärmt ist, gibt es keinen messbaren Unterschied mehr zwischen den beiden Versionen der Schleife.