Einige Leistungsmessungen verwenden, timeit
anstatt zu versuchen, dies manuell zu tun time
.
Zunächst Apple 2.7.2 64-Bit:
In [37]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.05 s per loop
Jetzt python.org 3.3.0 64-Bit:
In [83]: %timeit collections.deque((x for x in range(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.32 s per loop
In [84]: %timeit collections.deque((x for x in xrange(10000000) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.31 s per loop
In [85]: %timeit collections.deque((x for x in iter(range(10000000)) if x%4 == 0), maxlen=0)
1 loops, best of 3: 1.33 s per loop
Offenbar 3.x range
ist wirklich ein bisschen langsamer als 2.x xrange
. Und die xrange
Funktion des OP hat nichts damit zu tun. (Kein Wunder, da ein einmaliger Anruf an den __iter__
Slot unter 10000000 Anrufen für alles, was in der Schleife passiert, wahrscheinlich nicht sichtbar ist, aber jemand hat ihn als Möglichkeit angesprochen.)
Aber es ist nur 30% langsamer. Wie wurde das OP 2x so langsam? Wenn ich die gleichen Tests mit 32-Bit-Python wiederhole, erhalte ich 1,58 gegenüber 3,12. Ich vermute also, dass dies ein weiterer Fall ist, in dem 3.x für 64-Bit-Leistung in einer Weise optimiert wurde, die 32-Bit-Leistung beeinträchtigt.
Aber ist das wirklich wichtig? Überprüfen Sie dies mit 3.3.0 64-Bit erneut:
In [86]: %timeit [x for x in range(10000000) if x%4 == 0]
1 loops, best of 3: 3.65 s per loop
Das Erstellen von list
dauert also mehr als doppelt so lange wie die gesamte Iteration.
Und was "verbraucht viel mehr Ressourcen als Python 2.6+" betrifft, so sieht es aus meinen Tests so aus, als ob ein 3.x range
genau die gleiche Größe wie ein 2.x hat xrange
- und selbst wenn es 10x so groß wäre, die unnötige Liste erstellt ist immer noch ungefähr 10000000x mehr ein Problem als alles, was die Bereichsiteration möglicherweise tun könnte.
Und was ist mit einer expliziten for
Schleife anstelle der C-Schleife im Inneren deque
?
In [87]: def consume(x):
....: for i in x:
....: pass
In [88]: %timeit consume(x for x in range(10000000) if x%4 == 0)
1 loops, best of 3: 1.85 s per loop
Es wurde also fast so viel Zeit in der for
Aussage verschwendet wie in der eigentlichen Arbeit der Iteration der range
.
Wenn Sie sich Gedanken über die Optimierung der Iteration eines Bereichsobjekts machen, suchen Sie wahrscheinlich an der falschen Stelle.
In der Zwischenzeit fragen Sie immer wieder, warum xrange
entfernt wurde, egal wie oft Ihnen die Leute dasselbe sagen, aber ich werde es noch einmal wiederholen: Es wurde nicht entfernt: Es wurde umbenannt in range
und das 2.x range
wurde entfernt.
Hier ist ein Beweis dafür, dass das 3.3- range
Objekt ein direkter Nachkomme des 2.x- xrange
Objekts (und nicht der 2.x- range
Funktion) ist: die Quelle für 3.3range
und 2.7xrange
. Sie können sogar den Änderungsverlauf sehen (der meiner Meinung nach mit der Änderung verknüpft ist, die die letzte Instanz der Zeichenfolge "xrange" an einer beliebigen Stelle in der Datei ersetzt hat).
Warum ist es langsamer?
Zum einen haben sie viele neue Funktionen hinzugefügt. Zum anderen haben sie überall alle Arten von Änderungen vorgenommen (insbesondere innerhalb der Iteration), die geringfügige Nebenwirkungen haben. Und es gab viel Arbeit, um verschiedene wichtige Fälle dramatisch zu optimieren, auch wenn es manchmal weniger wichtige Fälle leicht pessimiert. Addiere das alles und ich bin nicht überrascht, dass das Iterieren eines range
so schnellen wie möglich jetzt etwas langsamer ist. Es ist einer dieser weniger wichtigen Fälle, auf die sich niemand jemals genug konzentrieren würde. Es ist wahrscheinlich, dass niemand jemals einen realen Anwendungsfall hat, bei dem dieser Leistungsunterschied der Hotspot in seinem Code ist.
range
in Python 3.x istxrange
von Python 2.x. Es war tatsächlich Python 2.x,range
das entfernt wurde.