Stavo armeggiando con i generatori Python e la classe iterabile, solo per divertimento. Fondamentalmente volevo testare qualcosa di cui non sono mai stato tanto sicuro: le classi in Pythons hanno un overhead significativo ed è meglio fare affidamento sui metodi che implementano yield
invece di classi che implementano un protocollo iteratore, se è possibile.python - Overhead su looping su una classe iterable
non riuscivo a trovare una spiegazione soddisfacente su questo argomento in Google, così ho deciso di provare loro fuori da solo con questi due semplici script: func_iter.py
e class_iter.py
Ecco func_iter.py
:
#!/usr/bin/env python
import time
x = 0
def create_generator(num):
mylist = range(num)
for i in mylist:
yield i
t = time.time()
gen = create_generator(100000)
for i in gen:
x = x + i
print "%.3f" % (time.time() - t)
Ed ecco class_iter.py
:
#!/usr/bin/env python
import time
x = 0
class Generator(object):
def __init__(self, num):
self.start = 0
self.end = num
def __iter__(self):
return self
def next(self):
if self.start == self.end:
raise StopIteration
else:
self.start = self.start + 1
return self.start
t = time.time()
gen = Generator(100000)
for i in gen:
x = x + i
print "%.3f" % (time.time() - t)
allora ho fatto funzionare ciascuno di essi 10 volte utilizzando Thi s in bash (per class_iter.py
, per esempio):
for i in {1..10}; do ./class_iter.py; done
E qui sono i tempi medi di funzionamento per ciascuna di esse:
class_iter.py: 0.0864
func_iter.py: 0.0307
Ora, le mie domande sono:
- Are i miei metodi sono corretti? Il mio confronto è giusto?
- Se sì, perché la grande differenza? Perché lo
class_iter.py
ha impiegato quasi tre volte il tempo di esecuzione difunc_iter.py
? - In caso contrario, come posso migliorare i miei metodi o ottenere un confronto migliore?
EDIT: Come suggerito Dacav, ho anche provato a fare funzionare func_iter.py
utilizzando xrange
invece di range
. Ciò riduce il tempo di esecuzione medio a 0,0263 secondi.
Non penso che sia quello che voleva testare. Stai confrontando un generatore con un generatore qui, non con un generatore per il protocollo iteratore. Sì, la classe è ancora iterabile, ma (ad esempio) non è possibile mettere sotto controllo lo stato perché lo stato è un generatore che non è un membro della classe. – agf
Confermato! È ancora più lento per forse 0,002 secondi ~ è sicuro assumere che questa differenza è dovuta al tempo necessario per istanziare la classe? – bow
@bow: sì, istanza di classe + accesso alla variabile di istanza in '__iter__'. Se sei curioso di vedere cosa succede esattamente dietro le quinte, prova il modulo 'dis'. – georg