Aktualisierung: 2009-05-29
Vielen Dank für die vielen Anregungen und Ratschläge. Ich habe Ihre Vorschläge genutzt, um meinen Produktionscode im Durchschnitt 2,5 Mal schneller auszuführen als mein bestes Ergebnis vor ein paar Tagen. Am Ende war ich in der Lage, den Java-Code am schnellsten zu erstellen.
Lektionen:
-
Mein Beispielcode unten zeigt das Einfügen von primitiven Ints, aber der Produktionscode speichert tatsächlich Strings (mein Fehler). Als ich das korrigiert habe, stieg die Python-Ausführungszeit von 2,8 Sekunden auf 9,6 Sekunden. Das heißt, dass Java beim Speichern von Objekten auf Anhieb schneller war.
-
Aber das ist noch nicht alles. Ich hatte das Java-Programm wie folgt ausgeführt:
java -Xmx1024m SpeedTest
Wenn Sie jedoch die anfängliche Heap-Größe wie folgt festlegen, erzielen Sie eine enorme Verbesserung:
java -Xms1024m -Xmx1024m SpeedTest
Durch diese einfache Änderung wurde die Ausführungszeit um mehr als 50 % verkürzt. Das Endergebnis für meinen SpeedTest lautet also: Python 9,6 Sekunden. Java 6,5 Sekunden.
Ursprüngliche Frage:
Ich hatte den folgenden Python-Code:
import time
import sys
def main(args):
iterations = 10000000
counts = set()
startTime = time.time();
for i in range(0, iterations):
counts.add(i)
totalTime = time.time() - startTime
print 'total time =',totalTime
print len(counts)
if __name__ == "__main__":
main(sys.argv)
Auf meinem Rechner wurde es in etwa 3,3 Sekunden ausgeführt, aber ich wollte es schneller machen, also beschloss ich, es in Java zu programmieren. Ich nahm an, dass Java kompiliert ist und im Allgemeinen als schneller als Python angesehen wird, so dass ich einige große Vorteile sehen würde.
Hier ist der Java-Code:
import java.util.*;
class SpeedTest
{
public static void main(String[] args)
{
long startTime;
long totalTime;
int iterations = 10000000;
HashSet counts = new HashSet((2*iterations), 0.75f);
startTime = System.currentTimeMillis();
for(int i=0; i<iterations; i++)
{
counts.add(i);
}
totalTime = System.currentTimeMillis() - startTime;
System.out.println("TOTAL TIME = "+( totalTime/1000f) );
System.out.println(counts.size());
}
}
Dieser Java-Code tut also im Grunde dasselbe wie der Python-Code. Aber er wurde in 8,3 Sekunden statt in 3,3 Sekunden ausgeführt.
Zur Vereinfachung habe ich dieses einfache Beispiel aus einem realen Beispiel entnommen. Das kritische Element ist, dass ich (Set oder HashSet) habe, die mit einer Menge von Mitgliedern ähnlich wie das Beispiel endet.
Hier sind meine Fragen:
-
Wie kommt es, dass meine Python-Implementierung schneller ist als meine Java-Implementierung?
-
Gibt es eine bessere Datenstruktur als das HashSet (Java) zu verwenden, um eine eindeutige Sammlung zu halten?
-
Was würde die Python-Implementierung schneller machen?
-
Was würde die Java-Implementierung schneller machen?
UPDATE:
Vielen Dank an alle, die bis jetzt beigetragen haben. Bitte erlauben Sie mir, einige Details hinzuzufügen.
Ich habe meinen Produktionscode nicht beigefügt, da er recht komplex ist. Und er würde eine Menge Ablenkung erzeugen. Der Fall, den ich oben dargestellt habe, ist so einfach wie möglich. Damit meine ich, dass der Java-Put-Aufruf viel langsamer zu sein scheint als das add() des Python-Sets.
Die Java-Implementierung des Produktionscodes ist auch etwa 2,5 bis 3 Mal langsamer als die Python-Version - genau wie oben.
Ich mache mir keine Sorgen über die Aufwärmphase oder den Start-Overhead von vm. Ich möchte nur den Code von meiner startTime mit meiner totalTime vergleichen. Bitte kümmern Sie sich nicht mit anderen Fragen.
Ich habe das Hashset mit mehr als genug Eimern initialisiert, so dass es nie einen Rehash durchführen muss. (Ich werde immer im Voraus wissen, wie viele Elemente die Sammlung letztendlich enthalten wird.) Ich nehme an, man könnte argumentieren, dass ich es auf Iterationen/0,75 hätte initialisieren sollen. Aber wenn Sie es ausprobieren, werden Sie sehen, dass die Ausführungszeit nicht wesentlich beeinträchtigt wird.
Ich habe Xmx1024m für diejenigen eingestellt, die neugierig sind (mein Rechner hat 4GB Ram).
Ich verwende die Java-Version: Java(TM) SE Runtime Environment (Build 1.6.0_13-b03).
In der Produktionsversion von speichere ich eine Zeichenfolge (2-15 Zeichen) im HashSet, so dass ich keine Primitive verwenden kann, obwohl dies ein interessanter Fall ist.
Ich habe den Code viele, viele Male ausgeführt. Ich bin sehr zuversichtlich, dass der Python-Code zwischen 2,5 und 3 Mal schneller ist als der Java-Code.