¿Por qué Python es realmente más lento en algunos cálculos que Java? Las profundidades recursivas también son limitadas.

Esto, por supuesto, es una pregunta polémica.

Cuando los cálculos son significativamente más lentos en una implementación dada de Python que lo que ha medido en una referencia particular (C, Java o lo que elija para la comparación), existen varias razones posibles para la diferencia. Ninguno de ellos son limitaciones inherentes de Python, pero algunos surgen como consecuencia del diseño y la especificación del lenguaje de Python.

Las principales diferencias entre Python y Java son que Python es un lenguaje de enlace tardío, de tipo dinámico e interpretado, mientras que Java es un lenguaje de compilación estático y una especificación VM (máquina virtual).

(Python puede ejecutarse en una JVM: Jython es la implementación canónica de Python para ese entorno).

La principal implicación de estas diferencias es que un sistema (hardware o máquina virtual) que ejecuta un programa Python normal debe, normalmente, verificar la tabla de despacho del objeto cada vez que accede a cualquier método o atributo del objeto. Esto se debe a que los nombres (variables, referencias) pueden haber cambiado desde el acceso anterior. Esto puede causar una sobrecarga de rendimiento significativa en los tipos de cómputo que implican muchas iteraciones (bucles) sobre cualquier estructura de datos dada o incluso cualquier objeto individual.

(Solo porque fui un entero la última vez que realizamos bucles en este cálculo no significa que todavía me refiera a un entero esta vez … y solo porque el método __abs __ () del objeto int se refería a un bit particular de código de bytes o código de máquina sin procesar la última vez que des-referenciamos no significa que el objeto no haya sido “parcheado por un mono” por alguna otra parte de este ciclo, por lo tanto tenemos una sobrecarga dinámica de despacho).

Esa es la causa principal de las penalizaciones de rendimiento de Python en comparación con la mayoría de los otros lenguajes … con respecto a los cálculos numéricos.

La otra limitación importante de rendimiento de la implementación de CPython en particular (y que aún puede aplicarse, hasta cierto punto, a otras implementaciones) es el GIL (el “bloqueo global del intérprete” que coordina o bloquea el acceso de cada hilo a los objetos para preservar la integridad de esos objetos en cualquier trabajo de subprocesos múltiples).

El GIL es un problema importante para el código que ejecuta múltiples hilos. Cuando compara la VM implementada con la implementación C de Python (CPython) con la implementación de una JVM Java o una VM CLR de C # sharp, la mayor diferencia es la cantidad de esfuerzo que se ha dedicado al bloqueo de grano fino para permitir un mejor rendimiento para ejecutando código multiproceso. (Generalmente a expensas del código de subproceso único, entre otras compensaciones).

La contención de bloqueo alrededor del GIL generalmente no tiene mucho impacto en los cálculos numéricos, ya que a menudo no se implementan con subprocesos múltiples significativos. Sin embargo, si ese es el problema para su código, su mejor estrategia, bajo CPython, sería cambiar el código de ser multihilo, a usar casi la misma sintaxis y características usando el 16.6. multiprocesamiento – Interfaz de “subprocesamiento” basada en procesos – Soporte de documentación de Python v2.7.8. (Pero recomiendo esto principalmente si los cálculos se implementan en su propio código de subprocesos … lea más si sospecha que se debe a la contención de GIL en bibliotecas estándar o de terceros).

Tenga en cuenta que puede cerrar la brecha de rendimiento considerablemente simplemente ejecutando su código de Python en PyPy PyPy – Bienvenido a PyPy. Este es un sistema Python que puede realizar una optimización considerable del código de bytes de Python, ya que se ejecuta a través de su procesamiento JIT (justo a tiempo) (compilación justo a tiempo) y optimización adaptativa).

El JIT de PyPy puede, en algunos casos, mitigar la sobrecarga del despacho porque, para algunas rutas de código, puede determinar que no es posible cambiar algunos de los objetos involucrados en el ciclo, y así racionalizar algunas de esas referencias … al menos si entiendo lo que he leído y visto en algunas charlas del creador de PyPy correctamente).

Además, para obtener un mejor rendimiento para el cómputo numérico en Python, realmente, realmente desea usar NumPy – Numpy … y, tal vez, algunas de las herramientas relacionadas desarrolladas a su alrededor. Estos implementan una serie de operaciones de matriz y matriz / vector, muchas de las cuales se realizan a la velocidad total del sistema en código nativo optimizado. (Esta es la forma principal de evitar la sobrecarga de despacho de objetos a la que me referí anteriormente. Numpy impone algunas restricciones a sus tipos de matriz, lo que permite estas operaciones simplificadas).

Algunas otras opciones para acelerar Python son:

  • Numba – Numba – Proporciona decorador @jit y otras características que pueden aplicar algunas optimizaciones al código NumPy que luego puede ejecutarse en una extensión LLVM.
  • Cython: C-Extensions for Python … una herramienta para tomar porciones críticas de rendimiento de su código, anotarlas y compilarlas en módulos de máquinas nativas ( .so módulos en sistemas tipo Unix, .dll en MS Windows).

Obviamente, puede argumentar que tener que usar y aprender herramientas adicionales, o incluso probar diferentes implementaciones de lenguaje (como PyPy, IronPython para ejecutar bajo un C # CLR o Jython para ejecutar bajo una JVM) … esto puede verse como deficiencias significativas.

Por otro lado, una visión más práctica es que los beneficios de productividad de escribir su código en un lenguaje de muy alto nivel que pudo aprender mucho más rápido que el nivel inferior, las alternativas compiladas más detalladas aún pueden ser un gran compromiso para obtener su código hasta el punto donde su rendimiento es su principal preocupación. La disponibilidad de herramientas que luego le permiten mejorar gradualmente solo aquellas partes del código que representan cuellos de botella reales se puede abordar con un trabajo adicional relativamente mínimo.

O bien, puede aprender Java, C #, C / C ++, Go o algún otro idioma … y pasar mucho tiempo persiguiendo puntos y comas y volver a implementar código o encontrar y aprender a usar bibliotecas de terceros para su nuevo idioma que estaban entre los ” Las baterías incluyen “con Python.

More Interesting

¿Cuál es la estructura de datos más simple y eficiente para representar la topología molecular?

¿Cómo podemos dividir un conjunto dado de números (posiblemente negativos) en dos partes que tienen el mismo promedio?

¿Cuáles son los mejores algoritmos para el análisis de sentimientos?

¿Qué son los problemas NP-completos? ¿Cómo podemos resolverlos?

¿Cuáles son las diferencias entre un programa y un algoritmo?

Cómo ordenar la lista de números dada en orden de registro (n)

¿Qué algoritmo de aprendizaje automático es mejor para agrupar pequeños cuerpos de texto por tema / categoría?

¿Son necesarios los algoritmos y las clases de estructura de datos para hacer una clase de desarrollo de aplicaciones móviles?

Cómo implementar el mapa usando el árbol de búsqueda binario en Java

Como senior que busca postularse a empresas como Google, Palantir, etc., ¿cómo puedo mejorar mis estructuras de datos avanzadas, algoritmos y cursos de bioinformática y tener más confianza en mí mismo al ingresar a un aula y no pensar automáticamente que soy estúpido? ?

¿Qué hay de malo con este código básico de Python?

Los electrones son extraños. ¿Cómo conocen el camino más corto al suelo? ¿No tendrían que 'mirar' hacia adelante?

Cómo comprar un algoritmo de creación de mercado para acciones

¿De qué juez en línea puedo aprender algoritmos estándar y estructuras de datos?

¿Alguien puede aprender programación, algoritmos y estructuras de datos en tres meses y obtener el bronce en la Olimpiada Británica de Informática?