¿Por qué Python nativo en Linux es mucho más lento que con Wine?
Necesitaba gran potencia matemática para un script y decidí hacerlo en python por ser el lenguaje de alto nivel que me pareció más rápido (después de Vala) y porque se escribe rapidísimo. Después me dió por ver si mi programa podría funcionar en Windows, y lo ejecuté en Wine. Sorpresa.
Hice este pequeñísimo benchmark:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import random
import time
#comienzo cronómetro
crono_start = time.time()
for i in range(10000000+1) :
a = (i * 1e10) ** (1/2)
#stop cronómetro
crono_stop = time.time()
tiempo_transcurrido = crono_stop - crono_start
velocidad_media = i / tiempo_transcurrido
print "Se han hecho "+str(i)+" cálculos."
print "Los cálculos han ocupado "+str(tiempo_transcurrido)+" desesperantes segundos, con una velocidad media de "+str(velocidad_media)+" pasos por segundo."
Lo pruebo con los dos:
sh-4.0$ python benchmark.py
Se han hecho 10000000 cálculos.
Los cálculos han ocupado 8.26637911797 desesperantes segundos, con una velocidad media de 1209719.49838 pasos por segundo.
sh-4.0$ wine python benchmark.py
Se han hecho 10000000 cálculos.
Los cálculos han ocupado 5.77799987793 desesperantes segundos, con una velocidad media de <strong>1730702.70185</strong> pasos por segundo.La diferencia es notable, de 7/10 aproximadamente.
Para el cálculo de números aleatorios la diferencia es aún más notable. Modifico un poco el script:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import random
import time
#comienzo cronómetro
crono_start = time.time()
for i in range(10000000+1) :
random.random();
#stop cronómetro
crono_stop = time.time()
tiempo_transcurrido = crono_stop - crono_start
velocidad_media = i / tiempo_transcurrido
print "Se han hecho "+str(i)+" cálculos."
print "Los cálculos han ocupado "+str(tiempo_transcurrido)+" desesperantes segundos, con una velocidad media de "+str(velocidad_media)+" pasos por segundo."
Y lo pruebo de nuevo. La diferencia es de 65/100 aprox.
sh-4.0$ python benchmark2.py
Se han hecho 10000000 cálculos.
Los cálculos han ocupado 5.71487903595 desesperantes segundos, con una velocidad media de 1749818.31411 pasos por segundo.
sh-4.0$ wine python benchmark2.py
Se han hecho 10000000 cálculos.
Los cálculos han ocupado 3.73500013351 desesperantes segundos, con una velocidad media de 2677376.07564 pasos por segundo.sh-4.0$ python --version
Python 2.6.2
sh-4.0$ wine python --version
Python 2.6.2
sh-4.0$ uname -r
2.6.31.12-174.2.3.fc12.i686
sh-4.0$ wine --version
wine-1.1.32Triste...
EDITO: Los dos usaron el mismo % de CPU -o eso me pareció-. Agradecería si alguien sabe como medir el "consumo" de un programa (no en % actualmente si no durante toda su ejecución).
- Inicie sesión o regístrese para enviar comentarios
- 1095 lecturas


Estoy suponiendo que se debe al compilador usado para crear tus binarios. Pero como no tengo certezas aporto confusión. Hay importantes diferencias entre distintas versiones en una misma plataforma.
Primero, modifiqué el código para arreglar un error by one, hacerlo compatible con python3.1, hacerlo un poco más legible e imprimir información sobre el compilador:
#!/usr/bin/env python# -*- coding: utf-8 -*-
import random
import time
import sys
calculos = 10000000
crono_start = time.time()
for i in range(calculos) :
a = (i * 1e10) ** (1/2)
crono_stop = time.time()
tiempo_transcurrido = crono_stop - crono_start
velocidad_media = calculos / tiempo_transcurrido
print("\n", sys.version, "\n")
print("Se han hecho %d cálculos." % calculos)
print("Los cálculos han ocupado %.2f desesperantes segundos." % tiempo_transcurrido)
print("Con una velocidad media de %.2f pasos por segundo." % velocidad_media)
Estos son los resultados de la corrida en mi debian GNU/Linux sid amd64:
$ for e in python2.5 python2.6 python3.1; do $e programacion/python/warcry.py; done2.5.4 (r254:67916, Nov 19 2009, 22:14:20)
[GCC 4.3.4]
Se han hecho 10000000 cálculos.
Los cálculos han ocupado 5.52 desesperantes segundos.
Con una velocidad media de 1811611.89 pasos por segundo.
2.6.4+ (r264:75706, Jan 17 2010, 11:37:20)
[GCC 4.4.3 20100108 (prerelease)]
Se han hecho 10000000 cálculos.
Los cálculos han ocupado 6.08 desesperantes segundos.
Con una velocidad media de 1644833.68 pasos por segundo.
3.1.1+ (r311:74480, Jan 20 2010, 01:34:30)
[GCC 4.4.3 20100108 (prerelease)]
Se han hecho 10000000 cálculos.
Los cálculos han ocupado 6.34 desesperantes segundos.
Con una velocidad media de 1578360.05 pasos por segundo.
Aún no tengo los resultados para wine (no es fácil instalar estos msi..). Los publico más tarde.
Acabo de compilarme la versión 3.1.1 y le hice también los cambios de sintaxis. Ahora los resultados son más parecidos:
sh-4.0$ python3.1 benchmark.pySe han hecho 10000000 cálculos.
Los cálculos han ocupado 7.01309609413 desesperantes segundos, con una velocidad media de 1425903.74719 pasos por segundo.
sh-4.0$ python2.6 benchmark.py
Se han hecho 10000000 cálculos.
Los cálculos han ocupado 8.32056307793 desesperantes segundos, con una velocidad media de 1201841.73912 pasos por segundo.
wine ~/.wine/drive_c/Python31/python.exe benchmark.pySe han hecho 10000000 c�lculos.
Los c�lculos han ocupado 6.83599996567 desesperantes segundos, con una velocidad media de 1462843.77563 pasos por segundo.
wine ~/.wine/drive_c/Python26/python.exe benchmark.py
Se han hecho 10000000 cálculos.
Los cálculos han ocupado 5.95600008965 desesperantes segundos, con una velocidad media de 1678979.15539 pasos por segundo.
El curioso, la versión 3.1.1 parece mejorar mucho el rendimiento para Linux, mientras que lo empeora para Windows frente a la versión 2.6 que pulveriza a las demás :s
Prueba tú a ver qué te sale...
Instalar python en wine es muy fácil. Te bajas el msi de la página web y escribes en tu terminal normal y corriente:
msiexec /i instalador.msi¡Y ya sólo queda seguir las instrucciones!
El curioso, la versión 3.1.1 parece mejorar mucho el rendimiento para Linux, mientras que lo empeora para Windows frente a la versión 2.6 que pulveriza a las demás :s
Prueba tú a ver qué te sale...
Instalar python en wine es muy fácil. Te bajas el msi de la página web y escribes en tu terminal normal y corriente:
msiexec /i instalador.msi¡Y ya sólo queda seguir las instrucciones!
Había muy buenas razones para la mejora en linux i386... pero no las recuerdo
. Con respecto a Windows, sé que suele ser debido a que la versión de GCC disponible para windows por el encargado de mantenimiento suele estar un poco retrasada. Las compilaciones que se hacen con ICC para i386 con notoriamente mejores.
Ya había intentando msiexec pero el instalador se traba y debug me dice que esa orden no está disponible en AMD64 ¬¬. Seguiré intentando.
El curioso, la versión 3.1.1 parece mejorar mucho el rendimiento para Linux, mientras que lo empeora para Windows frente a la versión 2.6 que pulveriza a las demás :s
Prueba tú a ver qué te sale...
Instalar python en wine es muy fácil. Te bajas el msi de la página web y escribes en tu terminal normal y corriente:
msiexec /i instalador.msi¡Y ya sólo queda seguir las instrucciones!
Había muy buenas razones para la mejora en linux i386... pero no las recuerdo
. Con respecto a Windows, sé que suele ser debido a que la versión de GCC disponible para windows por el encargado de mantenimiento suele estar un poco retrasada. Las compilaciones que se hacen con ICC para i386 con notoriamente mejores.
Ya había intentando msiexec pero el instalador se traba y debug me dice que esa orden no está disponible en AMD64 ¬¬. Seguiré intentando.
¿?
wine --version
wine --version
wine-1.0.1Con respecto a los cambios, sería bueno que muestres la información de compilador y no dejes de arreglar el off-by-one (estás iterando una vez de más).
wine --version
wine-1.0.1Con respecto a los cambios, sería bueno que muestres la información de compilador y no dejes de arreglar el off-by-one (estás iterando una vez de más).
Actualiza tu wine en winehq.org, está muy desfasado.
En cuanto al compilador... yo hize ./configure, make, make install. Supongo que por la pinta se compiló con gcc.
~$ gcc --versiongcc (GCC) 4.4.2 20091222 (Red Hat 4.4.2-20)
Copyright (C) 2009 Free Software Foundation, Inc.
Esto es software libre; vea el código para las condiciones de copia. NO hay
garantía; ni siquiera para MERCANTIBILIDAD o IDONEIDAD PARA UN PROPÓSITO EN
PARTICULAR
Y lo del off-by-one no sé qué es :s
Off By One es un navegador web para las versiones de 32 bits del sistema operativo Microsoft Windows. Se distribuye de manera gratuita —freeware.
wine --version
wine-1.0.1Con respecto a los cambios, sería bueno que muestres la información de compilador y no dejes de arreglar el off-by-one (estás iterando una vez de más).
Actualiza tu wine en winehq.org, está muy desfasado.
En cuanto al compilador... yo hize ./configure, make, make install. Supongo que por la pinta se compiló con gcc.
~$ gcc --versiongcc (GCC) 4.4.2 20091222 (Red Hat 4.4.2-20)
Copyright (C) 2009 Free Software Foundation, Inc.
Esto es software libre; vea el código para las condiciones de copia. NO hay
garantía; ni siquiera para MERCANTIBILIDAD o IDONEIDAD PARA UN PROPÓSITO EN
PARTICULAR
Y lo del off-by-one no sé qué es :s
Off By One es un navegador web para las versiones de 32 bits del sistema operativo Microsoft Windows. Se distribuye de manera gratuita —freeware.
http://en.wikipedia.org/wiki/Off-by-one_error
Según leo en ese link, el off-by-one error es cuando un bucle de n repeticiones empieza en 1 o empieza en 0 y tú lo pones al revés.
¡Ah vale! Creo que ya lo pillé, que range se comporta distinto en 2.6 que en 3.1.
Tal vez no venga a cuento pero... ¿existe alguna forma de hacer un script compatible con ambas versiones sin escribir funciones raras de "si estamos en la 2.6, usar raw_input, si estamos en una >3.0, usar input"?
Según leo en ese link, el off-by-one error es cuando un bucle de n repeticiones empieza en 1 o empieza en 0 y tú lo pones al revés.
¡Ah vale! Creo que ya lo pillé, que range se comporta distinto en 2.6 que en 3.1.
Tal vez no venga a cuento pero... ¿existe alguna forma de hacer un script compatible con ambas versiones sin escribir funciones raras de "si estamos en la 2.6, usar raw_input, si estamos en una >3.0, usar input"?
¿?, Está mal en cualquier versión. range(x) devuelve una lista de x elementos (0, 1, 2 .. x-1), al iterar sobre una lista de x elementos iteras x veces (aunque el ultimo número sobre el que iteraste sea x-1).
No existe tan cosa, pero con python3.x viene un script que hace la conversión de cualquier script 2.x a 3.x.
Según leo en ese link, el off-by-one error es cuando un bucle de n repeticiones empieza en 1 o empieza en 0 y tú lo pones al revés.
¡Ah vale! Creo que ya lo pillé, que range se comporta distinto en 2.6 que en 3.1.
Tal vez no venga a cuento pero... ¿existe alguna forma de hacer un script compatible con ambas versiones sin escribir funciones raras de "si estamos en la 2.6, usar raw_input, si estamos en una >3.0, usar input"?
¿?, Está mal en cualquier versión. range(x) devuelve una lista de x elementos (0, 1, 2 .. x-1), al iterar sobre una lista de x elementos iteras x veces (aunque el ultimo número sobre el que iteraste sea x-1).
No existe tan cosa, pero con python3.x viene un script que hace la conversión de cualquier script 2.x a 3.x.
Hmmm... entonces range devuelve de cero a tantos números que tu le pongas... entonces
range(10)=[0,1,2,3,4,5,6,7,8,9]
Vale, entonces habría que usar la variable "calculos" como haces tú para que no te hiciera uno de más. Tienes razón.
Lo de que se comporta distinto lo decía por esto, aunque creo que no tiene nada que ver:
Python 2.6.2 (r262:71600, Aug 21 2009, 12:22:21)[GCC 4.4.1 20090818 (Red Hat 4.4.1-6)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Python 3.1.1 (r311:74480, Jan 22 2010, 18:32:36)[GCC 4.4.2 20091222 (Red Hat 4.4.2-20)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> range(10)
range(0, 10)