Supongamos que un programa se escribió en dos idiomas distintos, que sean el lenguaje X y el idioma Y, si sus compiladores generan el mismo código de bytes, ¿por qué debería usar el lenguaje X en lugar del idioma Y? ¿Qué define que un idioma es más rápido que otro?
Pregunto esto porque a menudo se ve que la gente dice cosas como: "C es el lenguaje más rápido, ATS es un lenguaje más rápido que C". Estaba tratando de entender la definición de "rápido" para los lenguajes de programación.
programming-languages
compilers
Rodrigo Valente
fuente
fuente
Respuestas:
Hay muchas razones que pueden considerarse para elegir un lenguaje X sobre un lenguaje Y. La legibilidad del programa, la facilidad de programación, la portabilidad a muchas plataformas, la existencia de buenos entornos de programación pueden ser tales razones. Sin embargo, consideraré solo la velocidad de ejecución según lo solicitado en la pregunta. La pregunta no parece considerar, por ejemplo, la velocidad del desarrollo.
Dos idiomas pueden compilarse con el mismo código de bytes, pero eso no significa que se producirá el mismo código,
En realidad, bytecode es solo código para una máquina virtual específica. Tiene ventajas de ingeniería, pero no introduce diferencias fundamentales con la compilación directa de un hardware específico. Por lo tanto, podría considerar comparar dos idiomas compilados para ejecución directa en la misma máquina.
Dicho esto, el problema de la velocidad relativa de los idiomas es antiguo y se remonta a los primeros compiladores.
Durante muchos años, en aquellos primeros tiempos, el profesional consideraba que el código escrito a mano era más rápido que el código compilado. En otras palabras, el lenguaje de máquina se consideraba más rápido que los lenguajes de alto nivel como Cobol o Fortran. Y fue, tanto más rápido como generalmente más pequeño. Los lenguajes de alto nivel aún se desarrollaron porque eran mucho más fáciles de usar para muchas personas que no eran informáticos. El costo de usar lenguajes de alto nivel incluso tenía un nombre: la relación de expansión, que podría referirse al tamaño del código generado (un tema muy importante en esos momentos) o al número de instrucciones realmente ejecutadas. El concepto era principalmente experimental, pero la proporción era mayor que 1 al principio, ya que los compiladores hicieron un trabajo bastante simple para los estándares actuales.
Así, el lenguaje de máquina fue más rápido que decir, Fortran.
Por supuesto, eso cambió con los años, a medida que los compiladores se volvieron más sofisticados, hasta el punto de que la programación en lenguaje ensamblador ahora es muy rara. Para la mayoría de las aplicaciones, los programas en lenguaje ensamblador compiten mal con el código generado al optimizar los compiladores.
Esto muestra que un problema importante es la calidad de los compiladores disponibles para el lenguaje considerado, su capacidad para analizar el código fuente y optimizarlo en consecuencia.
Esta capacidad puede depender en cierta medida de las características del lenguaje para enfatizar las propiedades estructurales y matemáticas de la fuente con el fin de facilitar el trabajo del compilador. Por ejemplo, un lenguaje podría permitir la inclusión de declaraciones sobre las propiedades algebraicas de las funciones definidas por el usuario, para permitir que el compilador use estas propiedades con fines de optimización.
El proceso de compilación puede ser más fácil, por lo tanto, produce un mejor código, cuando el paradigma de programación del lenguaje está más cerca de las características de las máquinas que interpretarán el código, ya sea una máquina real o virtual.
Otro punto es si los paradigmas implementados en el lenguaje están cerrados al tipo de problema que se está programando. Es de esperar que un lenguaje de programación especializado para paradigmas de programación específicos compile de manera muy eficiente características relacionadas con ese paradigma. Por lo tanto, la elección de un lenguaje de programación puede depender, por claridad y velocidad, de la elección de un lenguaje de programación adaptado al tipo de problema que se está programando.
La popularidad de C para la programación del sistema probablemente se deba al hecho de que C está cerca de la arquitectura de la máquina, y que la programación del sistema también está directamente relacionada con esa arquitectura.
Algún otro problema se programará más fácilmente, con una ejecución más rápida utilizando programación lógica y lenguajes de resolución de restricciones .
Los sistemas reactivos complejos se pueden programar de manera muy eficiente con lenguajes de programación síncronos especializados como Esterel, que incorpora conocimiento muy especializado sobre dichos sistemas y genera código muy rápido.
O para tomar un ejemplo extremo, algunos lenguajes son altamente especializados, como los lenguajes de descripción de sintaxis utilizados para programar analizadores. Un generador de analizadores no es más que un compilador para tales lenguajes. Por supuesto, Turing no está completo, pero estos compiladores son extremadamente buenos para su especialidad: producir programas de análisis eficientes. Al restringirse el dominio del conocimiento, las técnicas de optimización pueden ser muy especializadas y ajustadas muy finamente. Estos generadores de analizadores suelen ser mucho mejores de lo que se podría obtener escribiendo código en otro idioma. Hay muchos lenguajes altamente especializados con compiladores que producen un código excelente y rápido para una clase restringida de problemas.
Por lo tanto, al escribir un sistema grande, puede ser aconsejable no confiar en un solo idioma, sino elegir el mejor idioma para los diferentes componentes del sistema. Esto, por supuesto, plantea problemas de compatibilidad.
Otro punto que a menudo importa es simplemente la existencia de bibliotecas eficientes para los temas que se programan.
Finalmente, la velocidad no es el único criterio y puede estar en conflicto con otros criterios como la seguridad del código (por ejemplo, con respecto a la entrada incorrecta o la resistencia a los errores del sistema), el uso de la memoria, la facilidad de programación (aunque la compatibilidad de paradigma puede ayudar a que ), tamaño del código objeto, mantenibilidad del programa, etc.
La velocidad no siempre es el parámetro más importante. También puede adoptar diferentes formas, como la complejidad, que puede ser la complejidad promedio o la peor de las situaciones. Además, en un sistema grande como en un programa más pequeño, hay partes donde la velocidad es crítica y otras donde importa poco. Y no siempre es fácil determinar eso de antemano.
fuente
Si bien todo se ejecuta eventualmente en la CPU * , existen varias diferencias entre los diferentes idiomas. Aquí hay unos ejemplos.
Idiomas interpretados Algunos idiomas se interpretan en lugar de compilarse , por ejemplo, Python, Ruby y Matlab. Eso significa que el código Python y Ruby no se compila en código máquina, sino que se interpreta sobre la marcha. Es posible compilar Python y Ruby en una máquina virtual (ver siguiente punto). Ver también esta pregunta . Por lo general, la interpretación es más lenta que el código compilado por varias razones. La interpretación en sí misma no solo puede ser lenta, sino que también es más difícil hacer optimizaciones. Sin embargo, si su código pasa la mayor parte del tiempo en funciones de biblioteca (el caso de Matlab), el rendimiento no se verá afectado.
Máquina virtual Algunos idiomas se compilan en bytecode , un "código de máquina" inventado que luego se interpreta. Los ejemplos por excelencia son Java y C #. Si bien el código de bytes se puede convertir en código de máquina sobre la marcha, el código probablemente seguirá ejecutándose más lentamente. En el caso de Java, se utiliza una máquina virtual para la portabilidad. En el caso de C #, puede haber otras preocupaciones, como la seguridad.
Gastos generales Algunos idiomas intercambian eficiencia por seguridad. Por ejemplo, algunas versiones de Pascal verificarían que no acceda a una matriz fuera de los límites. El código C # está "administrado", y esto tiene un costo. Otro ejemplo común es la recolección de basura, que ahorra tiempo para el programador pero no es tan eficiente como la administración práctica de la memoria. Existen otras fuentes de sobrecarga, como la infraestructura para el manejo de excepciones o para soportar la programación orientada a objetos.
* De hecho, hoy en día los sistemas de alto rendimiento también ejecutan código en GPU e incluso en FPGA.
fuente
Hay diferentes factores para elegir X en lugar de Y, como
Algunos lenguajes son adecuados para desarrollar proyectos empresariales como C # o Python, pero, por otro lado, algunos son buenos para la programación de sistemas como C ++.
Debe determinar en qué plataforma va a trabajar y qué aplicación va a crear.
fuente
El lenguaje de programación "más rápido" que puede obtener con cualquier plataforma es el lenguaje ensamblador para el chipset con el que está tratando. En ese nivel no hay traducciones. Sin embargo, debe tener algún conocimiento de cómo el chipset ejecuta las instrucciones, especialmente aquellas que pueden hacer cosas en paralelo.
La conversión de C a ensamblaje es muy "superficial" ya que está cerca de uno a uno, pero es más legible. Sin embargo, tiene muchas capas por encima debido a las bibliotecas estándar para mejorar la portabilidad. No hay tantas cosas que el compilador necesitaría hacer para llegar al código de ensamblaje y las optimizaciones más fuertes generalmente están ahí para hacer cambios específicos de la máquina.
C ++ agrega un lenguaje más rico. Sin embargo, debido a que el lenguaje agrega tanta complejidad, es más difícil para el compilador crear un código óptimo para la plataforma.
Luego vamos al otro lado de la balanza. Lenguas interpretadas. Estos tienden a ser los más lentos porque, además de hacer el trabajo, se dedica un tiempo a analizar el código y convertirlo en llamadas de máquina.
Luego tenemos esos en el medio. Generalmente tienen una capa de máquina virtual que está optimizada para la plataforma. Y el compilador creará código para que se ejecute la máquina virtual. A veces esto sucede de una vez como perl o pascal o ruby o Python. O en varias etapas como Java.
Algunas de estas máquinas virtuales agregan la noción de un compilador JIT que también acelera el tiempo de ejecución al crear código de nivel de máquina en lugar de traducir el código de byte intermedio.
Algunas máquinas virtuales son de bajo nivel, lo que permite una menor traducción del código de bytes al código de la máquina. Lo que acelera las cosas mientras mantiene la portabilidad.
fuente
*p++=*q++;
would en muchas máquinas ha sido más rápido quearray1[i]=array2[i];
en muchos procesadores, pero a menudo lo contrario es cierto y, por lo tanto, los compiladores pueden terminar convirtiendo el antiguo estilo de código en el último, apenas una conversión "superficial".-O0
, no harás ninguna optimización. Las optimizaciones son una ventaja adicional que obtiene con el compilador, pero el lenguaje en sí mismo puede traducirse casi uno a uno en el ensamblaje.Un punto que aún no se ha mencionado es que en algunos idiomas, ejecutar el mismo código muchas veces siempre realizará la misma secuencia de acciones; por lo tanto, la computadora solo necesita determinar una vez lo que debe hacer la sección de código. Uno de los principales beneficios del "uso estricto" del dialecto de JavaScript es que una vez que el motor de JavaScript descubre lo que hace un código, puede utilizar esa información la próxima vez que se ejecute; sin "uso estricto", no puede.
Por ejemplo, en ausencia de "uso estricto", un código como:
puede devolver una variable X en el contexto de llamada inmediata, si hay una, o una variable X de un contexto de llamada externo, o puede regresar
Undefined
. Peor aún, en un bucle como:no hay forma de que el motor de JavaScript sepa qué
g()
podría hacer coni
[o parag
sí mismo para el caso. Dado queg
oi
podría legítimamente cambiarsei
a una cadena, el motor de JavaScript no puede simplemente usar una suma numérica y una comparación numérica en el ciclo, sino que debe, en cada paso a través del ciclo, verificar si alguna de las llamadas a funciones ha hecho algoi
og
. Por el contrario, en el dialecto de "uso estricto" [algo sensato], el motor JavaScipt puede examinar el código anterior y saber que cada pasada a través del bucle utilizará la misma variable numérica e invocará la misma función. Por lo tanto, solo tendrá que identificari
y funcionarg
una vez, en lugar de tener que buscarlos en cada pasada a través del ciclo, un gran ahorro de tiempo.fuente
Bueno, aquí hay algunas respuestas bastante profesionales, esta no está cerca de ellas, pero podría ser intuitiva para usted.
Es posible que haya escuchado muchas veces que cuando necesita realizar una tarea lo más rápido posible, desea escribir el código que lo ejecuta en conjunto. Esto se debe a que solo ejecuta comandos que realmente necesita para completar la tarea y nada más. Mientras que en un lenguaje de alto nivel podría implementar esta tarea en varias líneas, el compilador aún necesita traducirlos al lenguaje de máquina. Esta traducción no siempre es minimalista, ya que podría escribirla directamente. Eso significa que la máquina gastará muchos relojes en ejecutar comandos que podría ahorrar.
Aunque los compiladores son muy sofisticados hoy en día, todavía no son efectivos como pueden ser los mejores programadores de ensamblaje.
Continuando en esta dirección, esos comandos innecesarios crecen en su cantidad (generalmente) a medida que el lenguaje está más nivelado. (esto no es 100% cierto para todos los idiomas de alto nivel)
Entonces, para mí, el lenguaje X es más rápido que el lenguaje Y (en tiempo de ejecución) si para cierto código, el código de máquina de X es más corto que el de Y.
fuente
Es difícil responder esta pregunta definitivamente porque es muy compleja y multidimensional (es casi como, por ejemplo, comparar marcas de automóviles con criterios misceláneos), pero hay nuevos estudios científicos que incluyen un excelente repositorio de códigos conocido como código Rosetta ( descripción general de Wikipedia ). Esta encuesta de 2014 realizada por Nanz y Furia estudia esta pregunta de manera bastante definitiva y científica en base a los siguientes criterios típicos y un análisis cuantitativo raro de cualidades de código típicamente subjetivas. El resumen contiene algunos hallazgos y generalizaciones objetivamente fundamentados. (Esperemos que otros estudios basados en estos resultados se puedan hacer en el futuro).
RQ1. ¿Qué lenguajes de programación hacen que el código sea más conciso?
RQ2. ¿Qué lenguajes de programación se compilan en ejecutables más pequeños?
RQ3. ¿Qué lenguajes de programación tienen un mejor rendimiento en tiempo de ejecución?
RQ4. ¿Qué lenguajes de programación usan la memoria de manera más eficiente?
RQ5. ¿Qué lenguajes de programación son menos propensos a fallas?
fuente
Los lenguajes de computadora son solo una abstracción de comandos para explicarle a la computadora qué hacer.
Incluso puede escribir en el lenguaje informático
Python
y compilarlo con un compilador de C (cython).Teniendo esto en cuenta, la velocidad de los lenguajes informáticos no se puede comparar.
Pero puede comparar compiladores para el mismo idioma hasta cierto punto. Por ejemplo
GNU C
compilador versusIntel C
compilador. (Busque el punto de referencia del compilador)fuente