¿Qué características semánticas de Python (y otros lenguajes dinámicos) contribuyen a su lentitud?
Ninguna.
El rendimiento de las implementaciones de lenguaje es una función del dinero, los recursos y las tesis doctorales, no las características del lenguaje. Self es mucho más dinámico que Smalltalk y un poco más dinámico que Python, Ruby, ECMAScript o Lua, y tenía una VM que superó a todas las máquinas virtuales Lisp y Smalltalk existentes (de hecho, la distribución Self se envió con un pequeño intérprete Smalltalk escrito en Self , e incluso eso fue más rápido que la mayoría de las máquinas virtuales Smalltalk existentes, y fue competitivo y, a veces, incluso más rápido que las implementaciones de C ++ de la época.
Luego, Sun dejó de financiar Self e IBM, Microsoft, Intel y Co. comenzaron a financiar C ++, y la tendencia se invirtió. Los desarrolladores de Self dejaron Sun para comenzar su propia compañía, donde usaron la tecnología desarrollada para Self VM para construir una de las máquinas virtuales Smalltalk más rápidas de la historia (la VM Animorphic), y luego Sun volvió a comprar esa compañía y una versión ligeramente modificada de que Smalltalk VM ahora se conoce mejor con el nombre de "HotSpot JVM". Irónicamente, los programadores de Java desprecian los lenguajes dinámicos por ser "lentos", cuando de hecho, Javafue lento hasta que adoptó la tecnología del lenguaje dinámico. (Sí, es cierto: el HotSpot JVM es esencialmente una VM Smalltalk. El verificador de bytecode realiza muchas verificaciones de tipo, pero una vez que el verificador acepta el bytecode, la VM, y especialmente el optimizador y el JIT, en realidad no lo hacen mucho interés con los tipos estáticos!)
CPython simplemente no hace muchas de las cosas que hacen que los lenguajes dinámicos (o más bien el despacho dinámico) sean rápidos: compilación dinámica (JIT), optimización dinámica, línea especulativa, optimización adaptativa, des-optimización dinámica, retroalimentación / inferencia de tipo dinámico. También existe el problema de que casi toda la biblioteca básica y estándar está escrita en C, lo que significa que incluso si hace que Python 100x sea más rápido de repente, no le ayudará mucho, porque algo como el 95% del código ejecutado por un El programa Python es C, no Python. Si todo se escribiera en Python, incluso las aceleraciones moderadas crearían un efecto de avalancha, donde los algoritmos se vuelven más rápidos y las estructuras de datos centrales se hacen más rápidas, pero, por supuesto, las estructuras de datos centrales también se usan dentro de los algoritmos, y los algoritmos centrales y los datos centrales las estructuras se usan en todas partes,
Hay un par de cosas que son notoriamente malas para los lenguajes OO gestionados por memoria (dinámicos o no) en los sistemas actuales. La memoria virtual y la protección de memoria pueden ser un factor decisivo para el rendimiento de la recolección de basura en particular, y el rendimiento del sistema en general. Y es completamente innecesario en un lenguaje seguro para la memoria: ¿por qué protegerse contra accesos ilegales a la memoria cuando no hay ningún acceso a la memoria en el idioma para empezar? Azul ha descubierto usar MMU potentes y modernos (Intel Nehalem y más nuevos, y el equivalente de AMD) para ayudar a la recolección de basura en lugar de obstaculizarlo, pero a pesar de que es compatible con la CPU, los subsistemas de memoria actuales de los sistemas operativos principales no son lo suficientemente potentes para permitir esto (es por eso que JVM de Azul realmente se ejecuta virtualizado en el metal desnudo además el sistema operativo, no dentro de él).
En el proyecto Singularity OS, Microsoft ha medido un impacto de ~ 30% en el rendimiento del sistema al usar la protección MMU en lugar del sistema de tipos para la separación de procesos.
Otra cosa que Azul notó al construir sus CPU Java especializadas fue que las CPU convencionales modernas se centran en algo completamente incorrecto cuando intentan reducir el costo de las fallas de caché: intentan reducir la cantidad de fallas de caché a través de cosas como la predicción de ramificaciones, la captación previa de memoria, y así. Pero, en un programa OO altamente polimórfico, los patrones de acceso son básicamente pseudoaleatorios, simplemente no hay nada que predecir. Por lo tanto, todos esos transistores simplemente se desperdician, y lo que se debe hacer es reducir el costo de cada pérdida de caché individual. (El costo total es el costo de #misses *, la corriente principal intenta derribar el primero, Azul el segundo). Los Aceleradores de Computación Java de Azul podrían tener 20000 fallas concurrentes de caché en vuelo y aún avanzar.
Cuando comenzó Azul, pensaron que tomarían algunos componentes de E / S listos para usar y diseñarían su propio núcleo de CPU especializado, pero lo que realmente necesitaron hacer fue exactamente lo contrario: tomaron un estándar bastante estándar. plataforma RISC de 3 direcciones y diseñó su propio controlador de memoria, MMU y subsistema de caché.
tl; dr : La "lentitud" de Python no es una propiedad del lenguaje, sino a) su implementación ingenua (primaria), yb) el hecho de que las CPU y los SO modernos están específicamente diseñados para hacer que C funcione rápidamente, y las características que have for C no están ayudando (caché) o incluso perjudicando activamente (memoria virtual) el rendimiento de Python.
Y aquí puede insertar prácticamente cualquier lenguaje administrado por memoria con polimorfismo dinámico ad-hoc ... cuando se trata de los desafíos de una implementación eficiente, incluso Python y Java son prácticamente "el mismo lenguaje".