Я пытался понять, почему Python 3 на самом деле занимает много времени по сравнению с Python 2 в некоторых ситуациях, ниже приведены несколько случаев, которые я проверил с python 3.4 на python 2.7.
Примечание. Я рассмотрел некоторые вопросы, такие как Почему нет функции xrange в циклах Python3? и в python3 намного медленнее, чем python2 и Тот же код медленнее в Python3 по сравнению с Python2, но я чувствую, что я не понял фактическую причину этой проблемы.
Я пробовал этот кусок кода, чтобы показать, как он делает разницу:
MAX_NUM = 3*10**7
# This is to make compatible with py3.4.
try:
xrange
except:
xrange = range
def foo():
i = MAX_NUM
while i> 0:
i -= 1
def foo_for():
for i in xrange(MAX_NUM):
pass
Когда я попытался запустить эту программу с py3.4 и py2.7, я получил ниже Результаты.
Примечание. Эти статистические данные прошли через машину 64 bit
с процессором 2.6Ghz
и рассчитали время, используя time.time()
в одном цикле.
Output : Python 3.4
-----------------
2.6392083168029785
0.9724123477935791
Output: Python 2.7
------------------
1.5131521225
0.475143909454
Я действительно не думаю, что были внесены изменения в while
или xrange
с 2,7 до 3,4, я знаю, что range
был запущен, действуя как xrange
в py3.4, но, как говорится в документации
range()
теперь ведет себя какxrange()
, используемый для ведения, за исключением того, что он работает со значениями произвольного размера. Последнее больше не существует.
это означает, что изменение от xrange
до range
очень сильно отличается от имени, но работает с произвольными значениями.
Я также проверил дизассемблированный байт-код.
Ниже представлен дизассемблированный байтовый код для функции foo()
:
Python 3.4:
---------------
13 0 LOAD_GLOBAL 0 (MAX_NUM)
3 STORE_FAST 0 (i)
14 6 SETUP_LOOP 26 (to 35)
>> 9 LOAD_FAST 0 (i)
12 LOAD_CONST 1 (0)
15 COMPARE_OP 4 (>)
18 POP_JUMP_IF_FALSE 34
15 21 LOAD_FAST 0 (i)
24 LOAD_CONST 2 (1)
27 INPLACE_SUBTRACT
28 STORE_FAST 0 (i)
31 JUMP_ABSOLUTE 9
>> 34 POP_BLOCK
>> 35 LOAD_CONST 0 (None)
38 RETURN_VALUE
python 2.7
-------------
13 0 LOAD_GLOBAL 0 (MAX_NUM)
3 STORE_FAST 0 (i)
14 6 SETUP_LOOP 26 (to 35)
>> 9 LOAD_FAST 0 (i)
12 LOAD_CONST 1 (0)
15 COMPARE_OP 4 (>)
18 POP_JUMP_IF_FALSE 34
15 21 LOAD_FAST 0 (i)
24 LOAD_CONST 2 (1)
27 INPLACE_SUBTRACT
28 STORE_FAST 0 (i)
31 JUMP_ABSOLUTE 9
>> 34 POP_BLOCK
>> 35 LOAD_CONST 0 (None)
38 RETURN_VALUE
И ниже представлен дизассемблированный байт-код для функции foo_for()
:
Python: 3.4
19 0 SETUP_LOOP 20 (to 23)
3 LOAD_GLOBAL 0 (xrange)
6 LOAD_GLOBAL 1 (MAX_NUM)
9 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
12 GET_ITER
>> 13 FOR_ITER 6 (to 22)
16 STORE_FAST 0 (i)
20 19 JUMP_ABSOLUTE 13
>> 22 POP_BLOCK
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
Python: 2.7
-------------
19 0 SETUP_LOOP 20 (to 23)
3 LOAD_GLOBAL 0 (xrange)
6 LOAD_GLOBAL 1 (MAX_NUM)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 6 (to 22)
16 STORE_FAST 0 (i)
20 19 JUMP_ABSOLUTE 13
>> 22 POP_BLOCK
>> 23 LOAD_CONST 0 (None)
26 RETURN_VALUE
Если мы сравниваем оба байтовых кода, они создавали один и тот же дизассемблированный байт-код.
Теперь мне интересно, какое изменение с 2,7 до 3,4 действительно вызывает это огромное изменение в времени выполнения в данном фрагменте кода.