¿Por qué Python 3 es considerablemente más lento que Python 2? [duplicar]


Esta pregunta ya tiene una respuesta aquí:

He estado tratando de entender por qué Python 3 realmente está tomando mucho tiempo en comparación 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 ido a través de algunas de las preguntas como ¿Por qué no hay ninguna función xrange en Python3? y bucle en python3 mucho más lento que python2 y Mismo código más lento en Python3 en comparación con Python2, pero siento que no entiendo la razón real detrás de este problema.

He probado este fragmento 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 he intentado ejecutar este programa con py3. 4 y py2. 7 tengo a continuación resultado.

Nota: Estos las estadísticas llegaron a través de una máquina 64 bit con procesador 2.6Ghz y calcularon el tiempo usando time.time() en bucle único.

Output : Python 3.4
-----------------
2.6392083168029785
0.9724123477935791

Output: Python 2.7
------------------
1.5131521225
0.475143909454

Realmente no creo que haya habido cambios aplicados a while o xrange de 2.7 a 3.4, sé que range se ha comenzado a actuar como a xrange en py3. 4 pero como dice la documentación{[18]]}

range() ahora se comporta como xrange() solía comportarse, excepto que funciona con valores de tamaño arbitrario. Ya no existe.

Esto significa un cambio de xrange a range es muy igual a un cambio de nombre pero trabajando con valores arbitrarios.

También he verificado el código de bytes desmontado.

A continuación se muestra el código de bytes 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 bytes desmontado 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 desmontado.

Ahora me pregunto qué cambio de 2.7 a 3.4 está causando realmente este gran cambio en el tiempo de ejecución en la pieza de código.

Author: Community, 2015-07-21

1 answers

La diferencia está en la implementación del tipo int. Python 3.x utiliza el tipo entero de tamaño arbitrario (long en 2.x) exclusivamente, mientras que en Python 2.x para valores hasta sys.maxint se usa un tipo int más simple que usa un C long simple debajo del capó.

Una vez que limite sus bucles a long enteros, 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: {[14]]}

>>> timeit(bar, number=10000)
5.704327821731567

Python 3: {[14]]}

>>> timeit(bar, number=10000)
3.7299320790334605

Usé sys.maxsize ya que sys.maxint se eliminó de Python 3, pero el entero valor es básicamente el mismo.

La diferencia de velocidad en Python 2 se limita a los primeros (2 ** 63) - 1 enteros en 64 bits, (2 ** 31)-1 enteros en sistemas de 32 bits.

Dado que no puede usar el tipo long con xrange() en Python 2, no incluí una comparación para esa función.

 33
Author: Martijn Pieters,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-21 20:37:07