Lista de eficiencia de indexación (python 2 vs python 3)

Al responder a otra pregunta , sugerí usar timeit para probar la diferencia entre indexar una lista con enteros positivos y enteros negativos. Aquí está el código:

 import timeit t=timeit.timeit('mylist[99]',setup='mylist=list(range(100))',number=10000000) print (t) t=timeit.timeit('mylist[-1]',setup='mylist=list(range(100))',number=10000000) print (t) 

Corrí este código con Python 2.6:

 $ python2.6 test.py 0.587687015533 0.586369991302 

Luego lo ejecuté con python 3.2:

 $ python3.2 test.py 0.9212150573730469 1.0225799083709717 

Luego me rasqué la cabeza, hice una pequeña búsqueda en Google y decidí publicar estas observaciones aquí.

Sistema operativo: OS-X (10.5.8) – Intel Core2Duo

Eso me parece una diferencia bastante significativa (un factor de más de 1.5 diferencias). ¿Alguien tiene una idea de por qué python3 es mucho más lento, especialmente para una operación tan común?

EDITAR

He ejecutado el mismo código en mi escritorio Ubuntu Linux (Intel i7) y he logrado resultados comparables con python2.6 y python 3.2. Parece que este es un problema que depende del sistema operativo (o del procesador) (otros usuarios están viendo el mismo comportamiento en las máquinas con Linux, ver comentarios).

Editar 2

El banner de inicio se solicitó en una de las respuestas, así que aquí va:

 Python 2.6.4 (r264:75821M, Oct 27 2009, 19:48:32) [GCC 4.0.1 (Apple Inc. build 5493)] on darwin 

y:

 Python 3.2 (r32:88452, Feb 20 2011, 10:19:59) [GCC 4.0.1 (Apple Inc. build 5493)] on darwin 

ACTUALIZAR

Acabo de instalar versiones nuevas de python2.7.3 y python3.2.3 de http://www.python.org/download/

En ambos casos, tomé la

“Python xx3 Mac OS X 32 bit i386 / PPC Installer (para Mac OS X 10.3 a 10.6 [2])”

ya que estoy en OS X 10.5. Aquí están los nuevos tiempos (que son razonablemente consistentes a través de múltiples pruebas):

python 2.7

 $python2.7 test.py 0.577006101608 0.590042829514 

python 3.2.3

 $python3.2 test.py 0.8882801532745361 1.034242868423462 

Esto parece ser un artefacto de algunas comstackciones de Python 3.2. La mejor hipótesis en este momento es que todas las comstackciones de Intel de 32 bits tienen una desaceleración, pero ninguna de 64 bits sí. Siga leyendo para más detalles.

No hiciste suficientes pruebas para determinar nada. Repitiendo su prueba un montón de veces, obtuve valores que van desde 0.31 a 0.54 para la misma prueba, que es una gran variación.

Entonces, ejecuté tu prueba con 10x el número, y repeat=10 , usando un montón de diferentes instalaciones de Python2 y Python3. Desechando los resultados superiores e inferiores, promediando los otros 8 y dividiendo por 10 (para obtener un número equivalente a tus pruebas), esto es lo que vi:

  1. 0.52/0.53 Lion 2.6 2. 0.49/0.50 Lion 2.7 3. 0.48/0.48 MacPorts 2.7 4. 0.39/0.49 MacPorts 3.2 5. 0.39/0.48 HomeBrew 3.2 

Entonces, parece que 3.2 es en realidad un poco más rápido con [99] , y aproximadamente la misma velocidad con [-1] .

Sin embargo, en una máquina 10.5, obtuve estos resultados:

  1. 0.98/1.02 MacPorts 2.6 2. 1.47/1.59 MacPorts 3.2 

De vuelta en la máquina original (Lion), corrí en modo de 32 bits y obtuve esto:

  1. 0.50/0.48 Homebrew 2.7 2. 0.75/0.82 Homebrew 3.2 

Entonces, parece que lo que importa es 32 bits, y no Leopard vs. Lion, gcc 4.0 vs. gcc 4.2 o clang, diferencias de hardware, etc. Ayudaría a probar comstackciones de 64 bits bajo Leopard, con diferentes comstackdores, etc. ., pero desafortunadamente mi caja Leopard es una Intel Mini de primera generación (con una CPU Core Solo de 32 bits), así que no puedo hacer esa prueba.

Como evidencia circunstancial adicional, realicé un montón de otras pruebas rápidas en la caja Lion, y parece que 32 bits 3.2 es ~ 50% más lento que 2.x, mientras que 64 bits 3.2 es quizás un poco más rápido que 2. X. Pero si realmente queremos respaldar eso, alguien necesita elegir y ejecutar una verdadera suite de referencia.

De todos modos, mi mejor conjetura en este punto es que al optimizar la twig 3.x, nadie pone mucho esfuerzo en las comstackciones i386 Mac de 32 bits. Que en realidad es una opción razonable para que hayan hecho.

O, alternativamente, ni siquiera pusieron mucho esfuerzo en el período i386 de 32 bits. Esa posibilidad podría explicar por qué el OP vio 2.x y 3.2 dando resultados similares en una caja de linux, mientras que Otto Allmendinger vio que 3.2 era igualmente más lento que 2.6 en una caja de linux. Pero como ninguno de ellos mencionó si estaban ejecutando Linux de 32 bits o de 64 bits, es difícil saber si eso es relevante.

Todavía hay muchas otras posibilidades diferentes que no hemos descartado, pero esta parece ser la mejor.

Aquí hay un código que ilustra al menos parte de la respuesta:

 $ python Python 2.7.3 (default, Apr 20 2012, 22:44:07) [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import timeit >>> t=timeit.timeit('mylist[99]',setup='mylist=list(range(100))',number=50000000) >>> print (t) 2.55517697334 >>> t=timeit.timeit('mylist[99L]',setup='mylist=list(range(100))',number=50000000) >>> print (t) 3.89904499054 $ python3 Python 3.2.3 (default, May 3 2012, 15:54:42) [GCC 4.6.3] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import timeit >>> t=timeit.timeit('mylist[99]',setup='mylist=list(range(100))',number=50000000) >>> print (t) 3.9906489849090576 

python3 no tiene el tipo int antiguo.

El range() Python 3 range() es el range() Python 2 xrange() . Si desea simular el range() Python 2 range() en el código de Python 3, debe usar la list(range(num) . Cuanto mayor sea el num , mayor será la diferencia con su código original.

La indexación debe ser independiente de lo que se almacena dentro de la lista, ya que la lista almacena solo referencias a los objetos de destino. Las referencias son desatadas y todas del mismo tipo. El tipo de lista es, por lo tanto, una estructura de datos homogénea, técnicamente. La indexación significa convertir el valor del índice en la dirección de inicio + desplazamiento. El cálculo del desplazamiento es muy eficiente con, como máximo, una resta. Esta es una operación extra muy barata en comparación con las otras operaciones.