Ich habe vor kurzem begonnen, Java-Code zu vergleichen, um die besten Ergebnisse für mein Programm zu erzielen, und habe etwas Merkwürdiges bemerkt. Ich habe nämlich die folgenden Methoden getestet:
%Vor%und bekam diese Ergebnisse:
%Vor% Nach der Suche über SO (zB Is Math.max ( a, b) oder (a & gt; b)? a: b schneller in Java? ) es war sicher für mich, dass test1
nicht so viel langsamer sein sollte.
Diese Methoden wurden zufällig in 8 Threads in 30 Sekunden getestet und jeder von mir ausgeführte Benchmark scheint ähnlich zu sein.
Ich benutze jdk1.8.0_45
.
Warum ist also test1
mehr als 200 Mal langsamer als test0
?
Da Math.max
eine statische Funktion ist, kann der Compiler herausfinden, dass der Code gar nichts tut und einfach die Ausführung optimiert, indem er nicht ausgeführt wird!
Die Variable m
ist lokal für die Funktion, das Zuweisen ist nicht hilfreich, da sie nie gelesen wird.
Sie müssen sicherstellen, dass die Ausführung etwas ändert, so dass es vom Compiler nicht aggressiv optimiert wird.
Sie können beispielsweise einfach den Wert von m
am Ende des Tests drucken oder m
zu einer Klassenvariablen machen, auf die später zugegriffen werden kann, oder sogar das Ergebnis wie ursprünglich im Kommentar vorgeschlagen zusammenfassen.
Math.max(a,b)
kann sehr aggressiv / offensichtlich in eine native Anweisung für den Prozessor optimiert werden.
Für das ternäre System wäre die einfache Umwandlung in einen Prozessorbefehl ein Vergleich + Sprung, besonders der Sprung ist teuer.
Um das ternäre in das JIT (Just-in-time-Compiler) zu optimieren, muss man erkennen, dass der Code ein Maximum ausdrückt und der native Befehl am besten ist.
Das JIT könnte dies eventuell erkennen, aber bis zu diesem Punkt wird es langsamer sein.
Nur um (in gewissem Maße) zu bestätigen, was Jean Logeart in seiner Antwort gesagt hat: Beim Hinzufügen eines trivialen main
das ruft beide Methoden auf, wie in
Und es in einem Hotspot Disassembler VM mit
ausführen %Vor% dann (auf Win7 / 64 mit Java 1.8.0_92) wird der letzte Maschinencode der Methode test0
sein
Ja, es tut im Grunde nichts.
Überraschenderweise macht das JIT offensichtlich für test1
eine ungerade Schleifenaufrollung, aber nicht scheint zu erkennen, dass die Methode nutzlos und nebenwirkungsfrei ist (es könnte weg optimiert werden, aber es ist nicht
Die resultierende Baugruppe ist ziemlich groß ....:
%Vor% Ich frage mich, warum die Methode nicht optimiert ist. Vielleicht ist es noch einmal wert, als separate Frage gefragt zu werden. Aber mein Bauchgefühl ist, dass es ein Nebeneffekt der künstlichen Testkonfiguration ist, die das letzte n
und die Verwendung der Schleifenvariable für den inneren Ausdruck beinhaltet. In ähnlichen (realistischeren) Aufbauten werden solche nutzlosen, nebenwirkungsfreien Methoden meist ziemlich zuverlässig eliminiert.
Wenn eine Methode zum ersten Mal ausgeführt wird, hatte die JVM nicht die Möglichkeit, die Methode mithilfe ihres Just-in-Time-Compilers erneut zu kompilieren. Dies ist das Problem mit so vielen Micro-Benchmark-Bemühungen. Angenommen, main () ruft test1 () auf, main () ruft test1 () mehrmals auf und misst die Zeit jedes Aufrufs von test1 (). Sie werden sehen, dass nachfolgende Aufrufe von test1 () viel schneller ausführen!
%Vor%Tags und Links java performance