Почему цикл по диапазону () в Python быстрее, чем при использовании цикла while? - PullRequest
68 голосов
/ 15 мая 2009

На днях я проводил некоторые тесты Python и наткнулся на что-то интересное. Ниже приведены две петли, которые делают более или менее одно и то же. Цикл 1 выполняется примерно вдвое дольше, чем цикл 2.

Петля 1:

int i = 0
while i < 100000000:
  i += 1

Петля 2:

for n in range(0,100000000):
  pass

Почему первый цикл намного медленнее? Я знаю, что это тривиальный пример, но это пробудило во мне интерес. Есть ли что-то особенное в функции range (), которая делает ее более эффективной, чем увеличение переменной таким же образом?

Ответы [ 5 ]

139 голосов
/ 15 мая 2009

см. Дизассемблирование байт-кода Python, вы можете получить более конкретную идею

использовать цикл while:

1           0 LOAD_CONST               0 (0)
            3 STORE_NAME               0 (i)

2           6 SETUP_LOOP              28 (to 37)
      >>    9 LOAD_NAME                0 (i)              # <-
           12 LOAD_CONST               1 (100000000)      # <-
           15 COMPARE_OP               0 (<)              # <-
           18 JUMP_IF_FALSE           14 (to 35)          # <-
           21 POP_TOP                                     # <-

3          22 LOAD_NAME                0 (i)              # <-
           25 LOAD_CONST               2 (1)              # <-
           28 INPLACE_ADD                                 # <-
           29 STORE_NAME               0 (i)              # <-
           32 JUMP_ABSOLUTE            9                  # <-
      >>   35 POP_TOP
           36 POP_BLOCK

Тело петли имеет 10 оп

диапазон использования:

1           0 SETUP_LOOP              23 (to 26)
            3 LOAD_NAME                0 (range)
            6 LOAD_CONST               0 (0)
            9 LOAD_CONST               1 (100000000)
           12 CALL_FUNCTION            2
           15 GET_ITER
      >>   16 FOR_ITER                 6 (to 25)        # <-
           19 STORE_NAME               1 (n)            # <-

2          22 JUMP_ABSOLUTE           16                # <-
      >>   25 POP_BLOCK
      >>   26 LOAD_CONST               2 (None)
           29 RETURN_VALUE

Тело цикла имеет 3 оп

Время выполнения кода на C намного меньше, чем intepretor, и его можно игнорировать.

31 голосов
/ 15 мая 2009

range() реализовано в C, тогда как i += 1 интерпретируется.

Использование xrange() может сделать его еще быстрее для больших чисел. Начиная с Python 3.0 range() совпадает с предыдущим xrange().

13 голосов
/ 18 апреля 2013

Надо сказать, что в цикле while происходит много созданий и разрушений объектов.

i += 1

совпадает с:

i = i + 1

Но поскольку Python-int неизменны, он не изменяет существующий объект; скорее это создает совершенно новый объект с новой ценностью. Это в основном:

i = new int(i + 1)   # Using C++ or Java-ish syntax

У сборщика мусора также будет много работы по очистке. «Создание объекта стоит дорого».

3 голосов
/ 15 мая 2009

Потому что вы работаете чаще в коде, написанном на C в интерпретаторе. то есть i + = 1 в Python, поэтому медленный (сравнительно), тогда как range (0, ...) - это один вызов C, цикл for будет выполняться в основном и в C.

2 голосов
/ 15 мая 2009

Большинство встроенных вызовов Python выполняются как C-код. Код, который должен быть интерпретирован, намного медленнее. С точки зрения эффективности памяти и скорости выполнения разница огромна. Внутренние компоненты Python были оптимизированы до предела, и лучше воспользоваться этими оптимизациями

...