sirve - tutorial python desde cero
¿Por qué Python 3 es considerablemente más lento que Python 2? (1)
Esta pregunta ya tiene una respuesta aquí:
He estado tratando de entender por qué Python 3 realmente toma mucho tiempo comparado con Python 2 en ciertas situaciones, a continuación se muestran algunos casos que he verificado de python 3.4 a python 2.7.
Nota: He revisado algunas de las preguntas como ¿Por qué no hay función xrange en Python3? y bucle en python3 mucho más lento que python2 y el mismo código más lento en Python3 en comparación con Python2 , pero creo que no entendí el motivo real de este problema.
He intentado esta pieza de código para mostrar cómo está haciendo la diferencia:
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
Cuando intenté ejecutar este programa con py3.4 y py2.7 obtuve los siguientes resultados.
Nota: Estas estadísticas llegaron a través de una máquina de 64 bit
con 2.6Ghz
procesador de 2.6Ghz
y calcularon el tiempo usando time.time()
en un solo ciclo.
Output : Python 3.4
-----------------
2.6392083168029785
0.9724123477935791
Output: Python 2.7
------------------
1.5131521225
0.475143909454
Realmente no creo que se hayan aplicado cambios a while
o xrange
de 2.7 a 3.4, sé que el range
ha comenzado a actuar como xrange
en py3.4, pero como dice la documentación
range()
ahora se comporta comoxrange()
usado para comportarse, excepto que funciona con valores de tamaño arbitrario. El último ya no existe.
esto significa que el cambio de xrange
a range
es muy similar a un cambio de nombre pero funciona con valores arbitrarios.
También he verificado el código de bytes desensamblado.
A continuación se muestra el código de byte desmontado para la función 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
Y debajo está el código de byte desensamblado para la función 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
Si comparamos ambos códigos de bytes, han producido el mismo código de bytes desmontados.
Ahora me pregunto qué cambio de 2.7 a 3.4 realmente está causando este gran cambio en el tiempo de ejecución en el fragmento de código dado.
La diferencia está en la implementación del tipo int
. Python 3.x utiliza el tipo de entero de tamaño arbitrario ( long
en 2.x) exclusivamente, mientras que en Python 2.x para valores de hasta sys.maxint
se usa un tipo de int
más simple que utiliza una C long
simple bajo el capó.
Una vez que limites tus loops a enteros long
, Python 3.x es más rápido:
>>> from timeit import timeit
>>> MAX_NUM = 3*10**3
>>> def bar():
... i = MAX_NUM + sys.maxsize
... while i > sys.maxsize:
... i -= 1
...
Python 2:
>>> timeit(bar, number=10000)
5.704327821731567
Python 3:
>>> timeit(bar, number=10000)
3.7299320790334605
sys.maxsize
porque sys.maxint
se eliminó de Python 3, pero el valor entero es básicamente el mismo.
La diferencia de velocidad en Python 2 se limita así al primer (2 ** 63) - 1 enteros en 64 bits, (2 ** 31) - 1 enteros en sistemas de 32 bits.
Como no puede usar el tipo long
con xrange()
en Python 2, no xrange()
una comparación para esa función.