Bawiłem się generatorami Pythona i klasą iteracyjną, tylko dla zabawy. Zasadniczo chciałem przetestować coś, czego nigdy nie byłem zbyt pewny: że klasy w Pythonach mają pewien znaczący narzut i lepiej jest polegać na metodach, które implementują yield
zamiast klas, które implementują protokół iteratora, jeśli możesz.python - Overhead on looping nad klasą iterowalną
nie mogłem znaleźć satysfakcjonujące wyjaśnienie na ten temat w Google, więc postanowiłem przetestować je na własną rękę za pomocą tych dwóch prostych skryptów: func_iter.py
i class_iter.py
Oto 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)
A oto 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)
I pobiegł każdy z nich 10 razy używając jes s w bash (dla class_iter.py
, na przykład):
for i in {1..10}; do ./class_iter.py; done
A oto średni czas eksploatacji dla każdej z nich:
class_iter.py: 0.0864
func_iter.py: 0.0307
Teraz moje pytania są następujące:
- Czy moje metody są poprawne? Czy moje porównanie jest sprawiedliwe?
- Jeśli tak, dlaczego ta duża różnica? Dlaczego
class_iter.py
wykonał prawie trzykrotnie dłużej niżfunc_iter.py
? - Jeśli nie, jak mogę poprawić swoje metody lub wymyślić lepsze porównanie?
EDIT: Jak sugeruje Dacav, próbowałem również uruchomiony func_iter.py
użyciu xrange
zamiast range
. Zmniejsza to średni czas działania do 0.0263 sekund.
Nie sądzę, że właśnie tego chciał przetestować. Porównywujesz tutaj generator z generatorem, a nie generator do protokołu iteratora. Tak, klasa jest nadal możliwa do sprawdzenia, ale (na przykład) nie można jej wybrać, ponieważ stan jest generatorem, który nie jest członkiem klasy. – agf
Potwierdzone! Wciąż trwa to dłużej niż 0,002 sekundy - czy można bezpiecznie założyć, że różnica ta wynika z czasu utworzenia klasy? – bow
@bow: tak, tworzenie klasy + dostęp do zmiennej instancji w '__iter__'. Jeśli jesteś ciekawy, co dokładnie dzieje się za kulisami, wypróbuj moduł 'dis'. – georg