Почему цикл в() в Python выполняется быстрее, чем использование цикла while?

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

Петля 1:

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

Петля 2:

for n in range(0,100000000):
  pass

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

Ответ 1

см. разборку байтового кода 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 op

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

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 op

Время запуска кода C намного короче, чем intepretor, и его можно игнорировать.

Ответ 2

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

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

Ответ 3

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

i += 1

совпадает с:

i = i + 1

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

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

У сборщика мусора также будет большой объем очистки. "Создание объекта дорого".

Ответ 4

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

Ответ 5

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