2009-05-28 4 views
12

O Groovy Gurus,Groovy für Schleifenausführungszeit

Dieser läuft Code-Schnipsel in etwa 1 Sekunde

for (int i in (1..10000000)) { 
     j = i; 
    } 

während dieses

for (int i = 1; i < 10000000; i++) { 
     j = i; 
    } 
fast 9 Sekunden dauert

Warum ist es so?

Antwort

9

Ok. Hier ist meine Meinung warum?

Wenn Sie beide Skripte Bytecode konvertieren, werden Sie feststellen, dass

  1. ForInLoop Bereich verwendet. Iterator wird verwendet, um während jeder Schleife voranzukommen. Vergleich (<) direkt auf int (oder Integer), um zu bestimmen, ob die Abbruchbedingung erfüllt ist oder nicht
  2. ForLoop verwendet traditionellen Schritt, überprüft Bedingung und Aktion ausführen. Für Zustand Überprüfung i < 10000000 nutzt ScriptBytecodeAdapter .compareLessThan abgefahrene. Wenn Sie tief den Code in das Verfahren graben, werden Sie beide Seiten des Vergleichs finden sich genommen in als Objekt und es gibt so viele Dinge, die sich, Gießen, sie als Objekt zu vergleichen usw.

ScriptBytecodeAdapter .compareLessThan - >ScriptBytecodeAdapter .compareTo ->DefaultTypeTransformation .compareTo

Es gibt andere Klassen in typehandling Paket, das speziell für die mathematischen Datentypen compareTo-Methode implementiert, nicht sicher, warum sie nicht verwendet werden, (wenn sie nicht verwendet wird)

ich, dass ich zu ahnen, ist der Grund, zweite Schleife länger nimmt. Bitte korrigieren Sie mich, wenn ich falsch liege oder etwas vermisse ...

+0

Das erklärt es fast sicher. Ich weiß, dass die for-Schleife im Java-Stil mehr Flexibilität bietet, was Sie tun können, aber sicherlich hätten sie eine Optimierung auf ihre grundlegendste (und am häufigsten verwendete) Form anwenden können, so dass sie genauso gut funktioniert wie die for..in-Schleife? Das ist eine kleine Performance-Falle für Leute, die aus Java oder C# kommen ... – Xiaofu

+0

Niemand erwartet jemals so viel Unterschied in diesen beiden Operationen. Bereiche, in denen sich Groovy verbessern könnte, zumal ähnlicher Code in Java in 300 mS ausgeführt wird. –

+1

+1 für den Bytecode suchen. – Leonel

2

In Ihrem Test sicher, dass die JVM bis zu „warm“, bevor die Maßnahme getroffen wird, sonst können Sie verschiedene Aktionen während des Starts in der Plattform (Klasse Laden, JIT-Kompilierung) aufzuwickeln auszulösen. Führen Sie Ihre Tests auch mehrmals hintereinander aus. Wenn Sie den zweiten Test durchgeführt haben, während ein Garbage Collect durchgeführt wurde, könnte das einen Einfluss haben. Versuchen Sie, jeden Ihrer Tests 100 mal auszuführen und die Zeiten nach jedem Test auszudrucken und sehen Sie, was Ihnen das sagt.

1

Wenn Sie potenzielle Artefakte aus der Startzeit beseitigen können, wie Jim es vorschlägt, würde ich vermuten, dass die Java-for-Schleife in Groovy nicht so gut implementiert ist wie die ursprüngliche Groovy-artige for-Schleife. Es wurde erst ab Version 1.5 nach Benutzeranforderungen hinzugefügt, daher war seine Implementierung vielleicht ein bisschen nachträglich.

Haben Sie einen Blick auf die für Ihre zwei Beispiele erzeugten Bytecode genommen, um zu sehen, ob es irgendwelche Unterschiede? Es gab eine Diskussion über Groovy Leistung here, in denen einer der Kommentare (von einem ‚johnchase‘) sagt dazu:

Ich frage mich, ob der Unterschied Sie sah erzählt, wie Groovy Anwendungen Zahlen (Primitive) - da es hüllt alle Primitiven in ihren entsprechenden Java-Wrapper-Klassen (int -> Integer), würde ich mir vorstellen, dass dies die Dinge ziemlich verlangsamen würde. Ich wäre daran interessiert zu sehen, die Leistung von Java-Code, der 10.000.000 Schleifen mit den Wrapper-Klassen statt Ints.

Also leidet die ursprüngliche Groovy for-Schleife nicht darunter? Nur Spekulationen von meiner Seite wirklich.

+0

Xiaofu, das sind gute Punkte. Was ich verwirrend finde, ist, dass die untere Schleife die schnellere sein sollte, da sie nur mit Ints arbeitet, nicht mit Ganzzahlen (obwohl der Typ von j nicht spezifiziert ist). Die obere Schleife sollte in der Sequenz langsamer sein. –