¿Qué gobierna la "velocidad" de un lenguaje de programación?
No existe la "velocidad" de un lenguaje de programación. Solo existe la velocidad de un programa particular escrito por un programador particular ejecutado por una versión particular de una implementación particular de un motor de ejecución particular que se ejecuta dentro de un entorno particular.
Puede haber grandes diferencias de rendimiento al ejecutar el mismo código escrito en el mismo idioma en la misma máquina usando diferentes implementaciones. O incluso usando diferentes versiones de la misma implementación. Por ejemplo, ejecutar exactamente el mismo punto de referencia ECMAScript en la misma máquina usando una versión de SpiderMonkey de hace 10 años frente a una versión de este año probablemente producirá un aumento de rendimiento en cualquier lugar entre 2 × –5 ×, tal vez incluso 10 ×. ¿Eso significa que ECMAScript es 2 veces más rápido que ECMAScript, porque ejecutar el mismo programa en la misma máquina es 2 veces más rápido con la implementación más reciente? Eso no tiene sentido.
¿Tiene esto algo que ver con la gestión de la memoria?
Realmente no.
¿Por qué pasó esto?
Recursos. Dinero. Microsoft probablemente emplea a más personas que preparan café para sus programadores compiladores que toda la comunidad PHP, Ruby y Python combinada tiene personas trabajando en sus máquinas virtuales.
Para más o menos cualquier característica de un lenguaje de programación que afecte el rendimiento de alguna manera, también hay una solución. Por ejemplo, C (estoy usando C aquí como sustituto de una clase de lenguajes similares, algunos de los cuales incluso existían antes de C) no es seguro para la memoria, por lo que múltiples programas de C que se ejecutan al mismo tiempo pueden pisotear la memoria del otro Entonces, inventamos memoria virtual y hacemos que todos los programas de C pasen por una capa de indirección para que puedan fingir que son los únicos que se ejecutan en la máquina. Sin embargo, eso es lento, por lo que inventamos la MMU e implementamos memoria virtual en hardware para acelerarla.
¡Pero! ¡Los idiomas seguros para la memoria no necesitan todo eso! Tener memoria virtual no les ayuda en nada. En realidad, es peor: la memoria virtual no solo no ayuda a los lenguajes seguros para la memoria, la memoria virtual, incluso cuando se implementa en hardware, también afecta el rendimiento. Puede ser especialmente perjudicial para el rendimiento de los recolectores de basura (que es lo que utilizan un número significativo de implementaciones de lenguajes seguros para la memoria).
Otro ejemplo: las CPU de uso general modernas y modernas emplean trucos sofisticados para reducir la frecuencia de errores de caché. Muchos de esos trucos equivalen a tratar de predecir qué código se ejecutará y qué memoria se necesitará en el futuro. Sin embargo, para los idiomas con un alto grado de polimorfismo de tiempo de ejecución (p. Ej., Lenguajes OO) es realmente muy difícil predecir esos patrones de acceso.
Pero, hay otra manera: el costo total de las fallas de caché es el número de fallas de caché multiplicado por el costo de una falla de caché individual. Las CPU convencionales intentan reducir la cantidad de fallas, pero ¿qué pasaría si pudiera reducir el costo de una falla individual?
La CPU Azul Vega-3 fue diseñada específicamente para ejecutar JVM virtualizadas, y tenía una MMU muy poderosa con algunas instrucciones especializadas para ayudar a la recolección de basura y la detección de escape (el equivalente dinámico al análisis de escape estático) y potentes controladores de memoria, y todo el sistema Todavía podría progresar con más de 20000 errores de caché pendientes en vuelo. Desafortunadamente, como la mayoría de las CPU específicas del idioma, su diseño fue simplemente gastado y forzado por los "gigantes" Intel, AMD, IBM y similares.
La arquitectura de la CPU es solo un ejemplo que tiene un impacto en lo fácil o difícil que es tener una implementación de alto rendimiento de un lenguaje. Un lenguaje como C, C ++, D, Rust que se ajuste bien al modelo de programación de CPU convencional moderno será más fácil de crear que un lenguaje que tenga que "luchar" y eludir la CPU, como Java, ECMAScript, Python, Ruby PHP.
Realmente, todo es cuestión de dinero. Si gasta la misma cantidad de dinero para desarrollar un algoritmo de alto rendimiento en ECMAScript, una implementación de alto rendimiento de ECMAScript, un sistema operativo de alto rendimiento diseñado para ECMAScript, una CPU de alto rendimiento diseñada para ECMAScript como se ha gastado durante el último décadas para hacer que los lenguajes tipo C sean rápidos, entonces es probable que vea un rendimiento igual. Es solo que, en este momento, se ha gastado mucho más dinero haciendo que los lenguajes similares a C sean rápidos que los lenguajes similares a ECMAScript rápidos, y las suposiciones de los lenguajes similares a C se incorporan a toda la pila desde MMU y CPU a sistemas operativos y sistemas de memoria virtual hasta bibliotecas y frameworks.
Personalmente, estoy más familiarizado con Ruby (que generalmente se considera un "lenguaje lento"), por lo que daré dos ejemplos: la Hash
clase (una de las estructuras de datos centrales en Ruby, un diccionario de valores clave) en Rubinius La implementación de Ruby está escrita en Ruby 100% puro, y tiene aproximadamente el mismo rendimiento que elHash
clase en YARV (la implementación más utilizada), que está escrita en C. Y hay una biblioteca de manipulación de imágenes escrita como una extensión C para YARV, que también tiene una "versión alternativa" pura (lenta) de Ruby para implementaciones que no no es compatible con C, que utiliza un montón de trucos de Ruby altamente dinámicos y reflexivos; una rama experimental de JRuby, que utiliza el marco de interpretación Truffle AST y el marco de compilación Graal JIT de Oracle Labs, puede ejecutar esa "versión alternativa" pura de Ruby tan rápido como el YARV puede ejecutar la versión C altamente optimizada original. Esto es simplemente (bueno, cualquier cosa menos) logrado por algunas personas realmente inteligentes que hacen cosas realmente inteligentes con optimizaciones dinámicas de tiempo de ejecución, compilación JIT y evaluación parcial.