Któregoś dnia robiłem testy porównawcze Pythona i znalazłem coś interesującego. Poniżej znajdują się dwie pętle, które robią mniej więcej to samo. Wykonanie pętli 1 trwa około dwa razy dłużej niż pętli 2.
Pętla 1:
int i = 0
while i < 100000000:
i += 1
Pętla 2:
for n in range(0,100000000):
pass
Dlaczego pierwsza pętla jest o wiele wolniejsza? Wiem, że to trywialny przykład, ale wzbudził moje zainteresowanie. Czy jest coś szczególnego w funkcji range (), która czyni ją bardziej wydajną niż zwiększanie zmiennej w ten sam sposób?
python
performance
benchmarking
A. Dorton
źródło
źródło
while
pętla musi wykonać porównanie każdej iteracji?range()
jest zaimplementowany w C, podczas gdyi += 1
jest interpretowany.Używanie
xrange()
może sprawić, że będzie to jeszcze szybsze w przypadku dużych liczb. Począwszy od Pythona 3.0range()
przebiega tak samo, jak poprzednioxrange()
.źródło
Trzeba powiedzieć, że w pętli while odbywa się wiele tworzenia i niszczenia obiektów.
i += 1
jest taki sam jak:
i = i + 1
Ale ponieważ inte Pythona są niezmienne, nie modyfikuje istniejącego obiektu; raczej tworzy zupełnie nowy przedmiot o nowej wartości. To w zasadzie:
i = new int(i + 1) # Using C++ or Java-ish syntax
Odśmiecacz będzie miał również dużo do wyczyszczenia. „Tworzenie obiektów jest drogie”.
źródło
Ponieważ częściej uruchamiasz kod napisany w języku C w interpretatorze. tj. i + = 1 jest w Pythonie, więc wolno (względnie), podczas gdy range (0, ...) to jedno wywołanie w C, pętla for będzie wykonywana również głównie w C.
źródło
Większość wywołań metod wbudowanych w Pythonie jest uruchamianych jako kod C. Kod, który należy zinterpretować, jest znacznie wolniejszy. Pod względem wydajności pamięci i szybkości wykonywania różnica jest gigantyczna. Wewnętrzne elementy Pythona zostały maksymalnie zoptymalizowane i najlepiej jest skorzystać z tych optymalizacji.
źródło
Myślę, że tutaj odpowiedź jest nieco bardziej subtelna niż sugerują inne odpowiedzi, chociaż jej istota jest poprawna: pętla for jest szybsza, ponieważ więcej operacji odbywa się w C, a mniej w Pythonie .
Mówiąc dokładniej, w przypadku pętli for w C zachodzą dwie rzeczy, które w pętli while są obsługiwane w Pythonie:
W pętli while porównanie
i < 100000000
jest wykonywane w Pythonie, podczas gdy w pętli for zadanie jest przekazywane do iteratora programurange(100000000)
, który wewnętrznie wykonuje iterację (a zatem sprawdza granice) w C.W pętli while aktualizacja pętli
i += 1
odbywa się w Pythonie, podczas gdy w pętli for ponownie iteratorrange(100000000)
, napisany w C, wykonujei+=1
(lub++i
).Widzimy, że jest to połączenie obu tych rzeczy, które przyspiesza pętlę for, dodając je ręcznie, aby zobaczyć różnicę.
import timeit N = 100000000 def while_loop(): i = 0 while i < N: i += 1 def for_loop_pure(): for i in range(N): pass def for_loop_with_increment(): for i in range(N): i += 1 def for_loop_with_test(): for i in range(N): if i < N: pass def for_loop_with_increment_and_test(): for i in range(N): if i < N: pass i += 1 def main(): print('while loop\t\t', timeit.timeit(while_loop, number=1)) print('for pure\t\t', timeit.timeit(for_loop_pure, number=1)) print('for inc\t\t\t', timeit.timeit(for_loop_with_increment, number=1)) print('for test\t\t', timeit.timeit(for_loop_with_test, number=1)) print('for inc+test\t', timeit.timeit(for_loop_with_increment_and_test, number=1)) if __name__ == '__main__': main()
Próbowałem tego zarówno z liczbą 100000000 jako stałą, jak i zmienną,
N
co byłoby bardziej typowe.# inline constant N while loop 3.5131139 for pure 1.3211338000000001 for inc 3.5477727000000003 for test 2.5209639 for inc+test 4.697028999999999 # variable N while loop 4.1298240999999996 for pure 1.3526357999999998 for inc 3.6060175 for test 3.1093069 for inc+test 5.4753364
Jak widać, w obu przypadkach
while
czas jest bardzo zbliżony do różnicyfor inc+test
ifor pure
. Zauważ również, że w przypadku, gdy używamyN
zmiennej,while
ma dodatkowe spowolnienie w celu wielokrotnego sprawdzania wartościN
, alefor
nie.To naprawdę szalone, że takie trywialne modyfikacje mogą skutkować ponad 3-krotnym przyspieszeniem kodu , ale to właśnie Python dla Ciebie. I nawet nie zaczynaj od tego, kiedy w ogóle możesz użyć wbudowanego na pętli ....
źródło