На днях я проводил тестирование Python и наткнулся на кое-что интересное. Ниже приведены две петли, которые делают примерно то же самое. Цикл 1 занимает примерно вдвое больше времени, чем цикл 2.
Петля 1:
int i = 0
while i < 100000000:
i += 1
Цикл 2:
for n in range(0,100000000):
pass
Почему первый цикл намного медленнее? Я знаю, что это банальный пример, но он вызвал у меня интерес. Есть ли что-то особенное в функции range (), что делает ее более эффективной, чем увеличение переменной таким же образом?
python
performance
benchmarking
А. Дортон
источник
источник
while
цикл должен выполнять сравнение на каждой итерации?range()
реализован в C, тогда какi += 1
как интерпретируется.Использование
xrange()
может сделать его еще быстрее для больших чисел. Начиная с Python 3.0range()
, как и раньшеxrange()
.источник
Надо сказать, что в цикле while происходит много создания и уничтожения объектов.
i += 1
такой же как:
i = i + 1
Но поскольку целые значения Python неизменяемы, он не изменяет существующий объект; скорее он создает совершенно новый объект с новой ценностью. Это в основном:
i = new int(i + 1) # Using C++ or Java-ish syntax
Сборщику мусора также предстоит большая работа по очистке. «Создание объекта - дорогое удовольствие».
источник
Потому что вы чаще работаете с кодом, написанным на C в интерпретаторе. т.е. i + = 1 находится в Python, поэтому он медленный (сравнительно), тогда как range (0, ...) - это один вызов C, цикл for будет выполняться в основном и в C.
источник
Большинство вызовов встроенных методов Python выполняется как код C. Код, который нужно интерпретировать, работает намного медленнее. С точки зрения эффективности памяти и скорости выполнения разница огромна. Внутреннее устройство Python было оптимизировано до крайности, и лучше всего воспользоваться этой оптимизацией.
источник
Я думаю, что ответ здесь немного более тонкий, чем предполагают другие ответы, хотя суть его верна: цикл for быстрее, потому что больше операций происходит на C и меньше на Python .
В частности, в случае цикла for в C происходят две вещи, которые в цикле while обрабатываются в Python:
В цикле while сравнение
i < 100000000
выполняется в Python, тогда как в цикле for задание передается итераторуrange(100000000)
, который внутренне выполняет итерацию (и, следовательно, проверку границ) в C.В цикле while обновление цикла
i += 1
происходит в Python, тогда как в цикле for снова итераторrange(100000000)
, написанный на C, выполняетi+=1
(или++i
).Мы видим, что комбинация этих двух вещей ускоряет цикл for, добавляя их вручную, чтобы увидеть разницу.
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()
Я пробовал это как с числом 100000000 - буквальной константой, так и с переменной,
N
что было бы более типично.# 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
Как видите, в обоих случаях
while
время очень близко к разницеfor inc+test
иfor pure
. Также обратите внимание, что в случае, когда мы используемN
переменную,while
имеет дополнительное замедление для многократного поиска значенияN
, ноfor
не делает.Это действительно безумие, что такие тривиальные модификации могут привести к ускорению кода более чем в 3 раза , но это Python для вас. И даже не заставляйте меня начинать, когда вы вообще можете использовать встроенную функцию над циклом ....
источник