Große Ausführungszeit Unterschied zwischen java Lambda-vs Anonyme Klasse
War ich neugierig auf die Leistung der Schaffung von java8 lambda-Instanzen, gegen die gleiche anonyme Klasse. (Messung erfolgt auf win32-java build 1.8.0-ea-b106). Ich habe sehr einfaches Beispiel, und gemessen wenn java vorschlagen, einige Optimierung von new
Bediener beim erstellen lambda-Ausdruck:
static final int MEASURES = 1000000;
static interface ICallback{
void payload(int[] a);
}
/**
* force creation of anonymous class many times
*/
static void measureAnonymousClass(){
final int arr[] = {0};
for(int i = 0; i < MEASURES; ++i){
ICallback clb = new ICallback() {
@Override
public void payload(int[] a) {
a[0]++;
}
};
clb.payload(arr);
}
}
/**
* force creation of lambda many times
*/
static void measureLambda(){
final int arr[] = {0};
for(int i = 0; i < MEASURES; ++i){
ICallback clb = (a2) -> {
a2[0]++;
};
clb.payload(arr);
}
}
(Vollständigen code können dort getroffen werden: http://codepad.org/Iw0mkXhD) Das Ergebnis ist eher vorhersehbar - lambda gewinnt 2 mal.
Aber wirklich wenig zu verschieben, um Verschluss zeigt sehr schlechte Zeit für die lambda. Anonyme Klasse gewinnt 10 mal!!!
So, jetzt anonyme Klasse sieht wie folgt aus:
ICallback clb = new ICallback() {
@Override
public void payload() {
arr[0]++;
}
};
Lambda funktioniert wie folgt:
ICallback clb = () -> {
arr[0]++;
};
(Vollständigen code können dort getroffen werden: http://codepad.org/XYd9Umty )
Kann jemand mir erklären, warum existiert so groß (schlecht) Unterschied im Umgang mit der Schließung?
- Das ist ein sehr naiver Ansatz zu microbenchmarking. Zumindest verwenden
System.nanoTime
und die Einführung der " Wegwerf-Ausführungen zum Aufwärmen der JVM. MehrereSystem.gc()
Anrufe zwischen den Ausführungen wäre auch eine gute Idee. Idealerweise tun Sie dies mit Google Bremssattel oder Oracle-jmh. - eigentlich habe ich vorgesehen, dieser Hinweis, dass ist der Grund, warum ich 2 Messungen durchgeführt, wenn
measureLambda
zuerst ausgeführt, und wennmeasureLambda
läuft nachmeasureAnonymousClass
- ohne Auswirkungen auf alle! Und nanoTime zeigen können, Unterschied in der genauen Messung, aber nicht wenn ich Rede 10 mal - Meinst du 10 Sekunden? Auch, es hätte geholfen, wenn Sie enthalten den Hinweis zum ausführen von sowohl Auftragseingang als im text Ihrer Frage.
- oh Nein, für meine CPU: für den ersten Fall (wo die lambda gewinnt) 7ms vs 14ms, für den zweiten Fall (mit Verschluss wo die lambda verlieren) 160ms vs 20ms. Die änderung der Bestellung hat keinen Einfluss auf gemessene Zeit.
- Die Genauigkeit der
currentTimeMillis
ist oft auf dem Niveau von einem Zehntel einer Sekunde (Plattform-abhängig). Die Genauigkeit dernanoTime
ist in der Regel auf der Ebene einer Mikrosekunde. Auch, nur die Neuordnung Ausführungen beweist gar nichts: jeder code-Pfad muss erwärmt werden, bis auf seine eigenen. Warm-up-Ausführungen ist der Weg, es zu tun und garbage collection muss überwacht werden, für. - Sie erstellen ein neues Objekt in jeder iteration, dann ist das eine riesige Anzahl von Objekten. Sie wenig tun, außer, dass (nur eine Methode aufrufen, die hat einen trivialen operation). GC konnte noch Dominieren die insgesamt verbrachte Zeit.
- es ist kein Problem mit den GC - da beide Fälle DIE GLEICHE ANZAHL VON ZUWEISUNGEN. Erste Programm nicht verwenden Schließung zweite Programm verwenden. Hast du jemals versucht zu verstehen, was die beiden Programme machen? Ich bin ganz damit einverstanden, dass viel Zeit damit verbracht wird, von GC, aber die gleiche Zeit in beiden Programmen! So ist dieses ständige Abweichung und keinen Unterschied, ob ich dies Messen mit warm-up oder mit nano - Messung. Nur zum Beweis meiner position, die ich gelegt habe, empfehlen Sie Google Bremssattel und warm-up! SIE KOMMENTARE SIND IRRELEVANT, weil die relative Anzahl der gleichzeitig x2 und x10.
- Hast du eigentlich Messen der GC-overhead, oder sind Sie nur raten? Winkende Hände und schrie, dass GC mal das gleiche mit absolut keinen festen Beweis ist nicht der Weg zur Erleuchtung. Zuweisungen sind gemessen in bytes, nicht in der Zuteilung rechnen. Sie haben zumindest eine solide Beweis dafür, dass in beiden Fällen die gleiche Anzahl von bytes ist reserviert?
- "Ich habe empfehlen Sie Google Bremssattel und warm-up!" --- Ich verstehe nicht diese Satz.
- Vielleicht fehlt der Punkt, der meine Kommentare so weit: es ist die Fälschung einer Reihe von standard-Hypothesen über die häufigsten Fehlerquellen beim benchmarking auf der JVM. Nur wenn Sie die solide gelöscht, können Sie geben Sie eine ernsthafte Diskussion der Ergebnisse.
- Beachten Sie, dass, neben der Tatsache, dass dieser "benchmark" ist weit entfernt von der beabsichtigten Anwendungsfall, nur die Angabe der
-server
option bei JVM-start wird die aufgenommene overhead gehen ganz Weg. - habe gerade versucht deine Empfehlung und bekommen genau das gleiche Ergebnis wie für reguläre JRE. Schließung in lambda langsamer als Verschluss für die anonyme Klasse in der Nähe der 10-mal.
Du musst angemeldet sein, um einen Kommentar abzugeben.
UPDATE
Einige Kommentare Wundern, wenn mein benchmark unten war fehlerhaft - nach der Einführung eine Menge von Zufälligkeiten (um zu verhindern, dass die JIT-Optimierung zu viel Zeug), noch bekomme ich ähnliche Ergebnisse, so Neige ich zu denken, es ist ok.
In der Zwischenzeit, ich bin gekommen, über diese Präsentation durch das lambda-team für die Umsetzung. Seite 16 zeigt einige Kennzahlen: innere Klassen und-Verschlüsse haben eine ähnliche Leistung /nicht-Erfassung von lambda sind bis zu 5x schneller.
Und @StuartMarks gepostet sehr interessanter link, die seziert lambda performance. Die Quintessenz ist, dass die post die JIT-Kompilierung, Lambda-Ausdrücke und anonyme Klassen führen in ähnlicher Weise auf aktuelle Hostpot JVM-Implementierungen.
IHRE BENCHMARK
Habe ich auch Ihr testen, wie du es gepostet hast. Das problem ist, dass es ausgeführt wird, für so wenig wie 20 ms für die erste Methode, und 2 ms für die zweite. Das ist zwar im Verhältnis 10:1, es ist in keiner Weise repräsentativ, da die Messzeit ist viel zu klein.
Habe ich dann modifiziert Ihr test, um zu ermöglichen, weitere JIT-warmup und ich ähnliche Ergebnisse erhalten wie mit jmh (d.h. kein Unterschied zwischen anonyme Klasse und lambda-Ausdruck).
Den letzten Lauf über 28 Sekunden für beide Methoden.
JMH MICRO-BENCHMARK
Habe ich der gleiche test mit jmh und die Quintessenz ist, dass die vier Methoden, die nehmen so viel Zeit, wie die entsprechenden:
In anderen Worten, die JIT-inlines-sowohl die anonyme Klasse und lambda-Ausdruck, und Sie nehmen genau die gleiche Zeit.
Zusammenfassung der Ergebnisse:
mvn exec:java -Dexec.mainClass="com.assylias.performance.RunTest"
- ist es richtige warm-up?java -jar target/microbenchmarks.jar '.*' -wi <warmup_iterations> -i <main_iterations>
. Ich bekomme nicht lange-Ausgang zum Aufwärmen, nur ein kurzer Hinweis "Warmup" iteration 1" etc.baseline
) und indirekte Anrufe auf lambda/anonyme Instanzen? Vielleicht ist die Zufälligkeit nicht behindern, Flucht-Analyse. Die Art und Weise, es zu brechen ist, indem Sie die Instanz in eine ArrayList oder ähnliches.