Alcune misurazioni delle prestazioni, usando timeit
invece di provare a farlo manualmente con time
.
Innanzitutto, Apple 2.7.2 a 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
Ora, python.org 3.3.0 a 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
A quanto pare, 3.x range
è davvero un po 'più lento di 2.x xrange
. E la xrange
funzione del PO non ha nulla a che fare con esso. (Non sorprende, dal momento che una chiamata una tantum allo __iter__
slot non è probabilmente visibile tra 10000000 chiamate a qualsiasi cosa accada nel loop, ma qualcuno lo ha sollevato come una possibilità.)
Ma è solo il 30% più lento. In che modo l'OP ha ottenuto 2x più lento? Bene, se ripeto gli stessi test con Python a 32 bit, ottengo 1,58 contro 3,12. Quindi la mia ipotesi è che questo è ancora un altro di quei casi in cui 3.x è stato ottimizzato per le prestazioni a 64 bit in modo da danneggiare 32-bit.
Ma importa davvero? Dai un'occhiata, con 3.3.0 di nuovo a 64 bit:
In [86]: %timeit [x for x in range(10000000) if x%4 == 0]
1 loops, best of 3: 3.65 s per loop
Quindi, la costruzione di list
richiede più del doppio dell'intera iterazione.
E per quanto riguarda "consuma molte più risorse di Python 2.6+", dai miei test, sembra che una 3.x range
abbia esattamente le stesse dimensioni di una 2.x xrange
- e, anche se fosse 10x più grande, costruendo l'elenco non necessario è ancora circa 10000000 volte più un problema di qualsiasi altra cosa possa fare l'iterazione dell'intervallo.
E che dire di un for
ciclo esplicito anziché del ciclo C all'interno 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
Quindi, quasi tutto il tempo perso for
nell'affermazione come nel lavoro effettivo di iterazione di range
.
Se sei preoccupato di ottimizzare l'iterazione di un oggetto range, probabilmente stai cercando nel posto sbagliato.
Nel frattempo, continui a chiederti perché è xrange
stato rimosso, non importa quante volte le persone ti dicono la stessa cosa, ma lo ripeterò di nuovo: non è stato rimosso: è stato rinominato range
e la 2.x range
è ciò che è stato rimosso.
Ecco alcune prove del fatto che l' range
oggetto 3.3 è un discendente diretto xrange
dell'oggetto 2.x (e non della range
funzione 2.x ): l'origine a 3.3range
e 2.7xrange
. Puoi persino vedere la cronologia delle modifiche (collegata, credo, alla modifica che ha sostituito l'ultima istanza della stringa "xrange" in qualsiasi punto del file).
Quindi, perché è più lento?
Bene, per uno, hanno aggiunto molte nuove funzionalità. Per un altro, hanno fatto tutti i tipi di cambiamenti in tutto il luogo (specialmente all'interno dell'iterazione) che hanno effetti collaterali minori. E c'era stato un sacco di lavoro per ottimizzare drasticamente vari casi importanti, anche se a volte pessimizza leggermente i casi meno importanti. Aggiungilo tutto e non mi sorprende che iterare il range
più velocemente possibile sia ora un po 'più lento. È uno di quei casi meno importanti su cui nessuno si preoccuperebbe mai abbastanza di concentrarsi. Nessuno probabilmente avrà mai un caso d'uso reale in cui questa differenza di prestazioni è l'hotspot nel proprio codice.
range
in Python 3.xxrange
proviene da Python 2.x. Fu infattirange
rimosso Python 2.x.