Python más rápido que C ++? ¿Como sucedió esto?

Estoy usando Windows7 usando CPython para python3.22 y g ++. Exe de MinGW para C ++ (lo que significa que uso libstdc ++ como la biblioteca de tiempo de ejecución). Escribí dos progtwigs simples para comparar su velocidad.

Pitón:

x=0 while x!=1000000: x+=1 print(x) 

C ++:

 #include  int main() { int x = 0; while ( x != 1000000 ) { x++; std::cout << x << std::endl; } return 0; } 

Ambos no optimizados.

Primero ejecuté c ++, luego ejecuté python a través de la línea de comandos interactivos, que es mucho más lento que iniciar directamente un archivo .py.

Sin embargo, python superó a c ++ y resultó ser más del doble de rápido. Python tomó 53 segundos, c ++ tomó 1 minuto y 54 segundos.

¿Se debe a que Python tiene una optimización especial para el intérprete o porque C ++ tiene que referirse a y std, lo que lo ralentiza y hace que ocupe un ram?
¿O es alguna otra razón?

Edición: Lo intenté de nuevo, con \n lugar de std::endl , y comstackndo con el indicador -O3 , esta vez tardó 1 minuto en llegar a 500,000.

No hay nada obvio aquí. Como Python está escrito en C, debe usar algo como printf para implementar la print . Las transmisiones de E / S de C ++, como cout , generalmente se implementan de una manera que es mucho más lenta que printf . Si desea poner a C ++ en una mejor posición, puede intentar cambiar a:

 #include  int main() { int x=0; while(x!=1000000) { ++x; std::printf("%d\n", x); } return 0; } 

Cambié a usar ++x lugar de x++ . Hace años, la gente pensaba que esta era una “optimización” valiosa. Tendré un ataque al corazón si ese cambio hace alguna diferencia en el rendimiento de su progtwig (OTOH, estoy seguro de que usar std::printf hará una gran diferencia en el rendimiento en tiempo de ejecución). En cambio, hice el cambio simplemente porque no estás prestando atención a lo que era el valor de x antes de incrementarlo, así que creo que es útil decir eso en el código.

Uno de mis colegas en el trabajo me dijo que el código Python es más rápido que el código C ++ y luego mostró este tema como ejemplo para demostrar su punto. Ahora resulta obvio a partir de otras respuestas que lo que está mal con el código C ++ publicado en la pregunta. ¡Todavía me gustaría resumir mis puntos de referencia que hice para mostrarle lo rápido que puede ser un buen código C ++!

Hay dos problemas con el código original de C ++:

  • Utiliza std::endl para imprimir una nueva línea en cada iteración. Esa es una muy mala idea porque std::endl hace más cosas que simplemente imprimir una nueva línea: también obliga a la secuencia a descargar el búfer acumulado hasta el momento; el lavado es una operación costosa , ya que tiene que lidiar con el hardware, el dispositivo de salida. Entonces, la primera solución es esta: si desea imprimir una nueva línea, simplemente use '\n' .

  • El segundo problema es menos obvio ya que no se ve en el código. Está en el diseño de flujos de C ++. De forma predeterminada, los flujos de C ++ se sincronizan con los flujos de C después de cada operación de entrada y salida para que su aplicación pueda mezclar std::cout y std::printf , y std::cin y std::scanf sin ningún problema. Esta función (sí, es una función ) no es necesaria en este caso, así que podemos deshabilitarla, ya que tiene una pequeña sobrecarga en tiempo de ejecución (eso no es un problema ; no hace que C ++ sea malo; es simplemente un precio para la característica ). Así que la segunda solución es la siguiente: std::cout::sync_with_stdio(false);

Y aquí está el código optimizado final:

 #include  int main() { std::ios_base::sync_with_stdio(false); int x = 0; while ( x != 1000000 ) { ++x; std::cout << x << '\n'; } } 

Y compile esto con banderas -O3 y ejecute (y mida ) como:

 $ g++ benchmark.cpp -O3 #comstacktion $ time ./a.out #run //.. real 0m32.175s user 0m0.088s sys 0m0.396s 

Y ejecute y mida el código de Python (publicado en la pregunta):

 $ time ./benchmark.py //... real 0m35.714s user 0m3.048s sys 0m4.456s 

El user y el tiempo del sistema nos dicen cuál es rápido y por qué orden .

Espero que te ayude a eliminar tus dudas. 🙂

Creo que necesitamos más información, pero espero que estés construyendo una versión no optimizada de C ++. Intenta construirlo con la bandera -O3 . (Alguien que conozca mejor a GCC tendrá más y mejores recomendaciones). Sin embargo, aquí hay algunos tiempos de una fuente completamente no confiable: http://ideone.com . Corrí cada 5 veces para obtener alguna medida de variación en el tiempo, pero solo el C ++ original varió, y no mucho.

Python: http://ideone.com/WBWB9 tiempo: 0.07-0.07s
Tu C ++: http://ideone.com/tzwQJ tiempo: 0.05-0.06s
C ++ modificado: http://ideone.com/pXJo3 tiempo: 0.00s-0.00s

En cuanto a por qué mi C ++ fue más rápido que el tuyo, std::endl obliga a C ++ a descargar el búfer inmediatamente. '\n' hace la nueva línea sin el vaciado del búfer forzado, que es mucho más rápido.

(Nota: solo corrí a 12773, ya que ideone.com mata los procesos después de mostrar una cierta cantidad de salida, eso era lo máximo que me daría el servidor)

std :: endl se retrasa, use ‘\ n’ hará que c ++ sea más rápido.

El mismo problema que se plantea en ¿Por qué la lectura de líneas de stdin es mucho más lenta en C ++ que en Python? pero en la dirección opuesta.

añadir

std::cout.sync_with_stdio(false);

a la cima del progtwig