¿Qué determina la "velocidad" de un lenguaje de programación?


38

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.


21
Si un programa es más rápido que otro, significa que no pueden tener el mismo código de bytes.
svick

55
Los idiomas son solo una noción que uno usa para escribir programas, por lo que realmente no puede hablar sobre la velocidad de un idioma.
Juho

1
@Raphael Siento que está fuera de tema, poco claro y demasiado amplio. Si bien el tema se adapta mejor a la Ingeniería de Software , sospecho que se cerraría como "demasiado amplio" allí.
David Richerby

2
Dejando de lado la implementación, la "velocidad" es ambigua, hay diferentes velocidades para implementar, compilar, ejecutar y depurar, y generalmente intercambiará algunos por los demás (de lo contrario, todos estaríamos usando el lenguaje de programación)
Nick T

Como anteriormente. Los idiomas no generan el mismo código de bytes. Algunos idiomas son más fáciles de analizar en código de bytes. Algunos tienen un mayor nivel de abstracción.
superluminario

Respuestas:


23

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.


Gracias. Es algo así. Estaba buscando. Fue difícil encontrar material para el tema. Esto se aclaró lo suficiente.
Rodrigo Valente

@ RodrigoAraújoValente Gracias, es posible que desee ver esta pregunta . Una visión extremista es que un compilador para el lenguaje L puede agrupar un intérprete para L con el código fuente del programa, sin hacer nada. Entonces puede hacerlo mejor intentando optimizar el cálculo del paquete (evaluación parcial). Cuanto más optimices y más rápido será tu idioma. La pregunta es entonces: ¿qué puede ayudarlo a optimizar? Las respuestas pueden incluir un buen conocimiento del área temática especializada, ayuda del programador, análisis sofisticado, etc.
babou

Por "mismo código de bytes" supongo que quiere decir "mismo tipo de representación ejecutable". Obviamente, los ejecutables idénticos se ejecutarán a la misma velocidad (suponiendo el mismo sistema de ejecución). (Probablemente lo habría visto desde una perspectiva de información / comunicación. En teoría , un programador puede saber todo sobre el programa y el hardware, mientras que un lenguaje a menudo restringe la comunicación (limitando las transformaciones permitidas o útiles) y el compilador puede no saber detalles de microarquitectura. La compilación y el desarrollo del compilador son análogos al desarrollo y la capacitación ...
Paul A. Clayton

Esto luego entra en lo que los humanos son generalmente buenos (por ejemplo, reconocer patrones generales) versus lo que las computadoras son generalmente buenas (por ejemplo, mantenimiento de registros y "aritmética"). Además, la comunicación de información de tiempo de ejecución suele ser más amigable con la computadora (la optimización guiada por perfil puede superar cierta falta de información comunicada a través del lenguaje de programación). La optimización dinámica no sería práctica con programadores humanos ...
Paul A. Clayton

(aunque podría decirse lo mismo de escribir todo el software ensamblado por programadores expertos que apunten a un hardware específico, para cuando el software se haya optimizado, no solo el hardware habría cambiado sino que el software quedaría obsoleto).)
Paul A. Clayton

16

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.


Entonces, básicamente, si necesito más rendimiento, ¿debería elegir idiomas compilados? ¿Y sobre los paradigmas? ¿Hay alguna razón para elegir funcional en lugar de oop, o viceversa?
Rodrigo Valente

Su comentario sobre la recolección de basura es un poco simplista. No siempre es decidible estáticamente cuando la memoria asignada ya no se usa. Incluso cuando es decidible, puede ser muy difícil de determinar sin cometer errores. Por lo tanto, GC a veces es necesario y a menudo más seguro (como comprobar los límites de la matriz). Además, se puede combinar con una versión explícita.
babou

@ RodrigoAraújoValente Depende. El código crappy a menudo se compilará en código crappy. Tal vez el código que puede escribir en Python es en realidad más rápido que el código que puede escribir en C.
Raphael

nit: como se explica en la pregunta a la que se vinculó, python no se interpreta "sobre la marcha" :)
Eevee

Ninguno de los idiomas que menciona en la sección interpretada se interpreta sobre la marcha. Python se compila a bytecode, Ruby se compiló a AST, pero creo que ahora se compila a bytecode. Matlab, creo que ahora está realmente compilado JIT. En realidad, no conozco ninguna implementación de lenguaje que no sea de nicho que interprete las cosas sobre la marcha en lugar de al menos compilar en algún tipo de representación de máquina virtual.
Winston Ewert

5

Hay diferentes factores para elegir X en lugar de Y, como

  • Facilidad de aprendizaje
  • Facilidad de comprensión
  • Velocidad de desarrollo
  • Ayuda con la aplicación del código correcto
  • Rendimiento del código compilado
  • Entornos de plataforma compatibles
  • Portabilidad
  • Adecuado para el propósito

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.


1
Entonces, ¿cómo determino el rendimiento del código compilado? Eso es básicamente lo que me hizo hacer esta pregunta.
Rodrigo Valente

66
Esta respuesta ciertamente tiene buenos consejos, pero no veo cómo responde a la pregunta, que trata sobre la velocidad como un factor de elección para un idioma.
babou

@ RodrigoAraújoValente Es posible que ni siquiera se compilen códigos (si se interpreta su idioma).
Raphael

1
Es posible que desee agregar "Buenas bibliotecas" y "Buenas herramientas".
Raphael

@ RodrigoAraújoValente Lo ejecutas y lo perfilas.
Kyle

2

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.


Históricamente, C fue diseñado para permitir una fácil traducción al código de máquina. Sin embargo, cada vez más, convertir C en código C eficiente requiere que un compilador descubra lo que un programador intentaba hacer y luego traduzca esa intención en código máquina. Por ejemplo, históricamente el código de máquina equivalente a *p++=*q++;would en muchas máquinas ha sido más rápido que array1[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".
supercat

Por lo general, si lo haces -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.
Arquímedes Trajano

2

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:

function f() { return x; }

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:

for (i=0; i<40; i+=1) { g(i); }

no hay forma de que el motor de JavaScript sepa qué g()podría hacer con i[o para gsí mismo para el caso. Dado que go ipodría legítimamente cambiarse ia 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 algo io g. 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 identificar iy funcionarg una vez, en lugar de tener que buscarlos en cada pasada a través del ciclo, un gran ahorro de tiempo.


2

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.


Montaje totalmente rocas. Sin embargo, se necesita un verdadero artista para superar a los mejores compiladores.
Johan - restablece a Mónica

1

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?

Resumen: a veces los debates sobre lenguajes de programación son más religiosos que científicos. Las preguntas sobre qué lenguaje es más sucinto o eficiente, o hace que los desarrolladores sean más productivos, se discuten con fervor, y sus respuestas se basan con demasiada frecuencia en anécdotas y creencias sin fundamento. En este estudio, utilizamos el potencial de investigación en gran parte sin explotar de Rosetta Code, un repositorio de código de soluciones para tareas de programación comunes en varios lenguajes, que ofrece un gran conjunto de datos para el análisis. Nuestro estudio se basa en 7.087 programas de solución correspondientes a 745 tareas en 8 lenguajes ampliamente utilizados que representan los principales paradigmas de programación (procesal: C y Go; orientado a objetos: C # y Java; funcional: F # y Haskell; secuencias de comandos: Python y Ruby). Nuestro análisis estadístico revela, en particular, que: los lenguajes funcionales y de secuencias de comandos son más concisos que los lenguajes de procedimiento y orientados a objetos; C es difícil de superar cuando se trata de velocidad bruta en entradas grandes, pero las diferencias de rendimiento con respecto a las entradas de tamaño moderado son menos pronunciadas y permiten que incluso los lenguajes interpretados sean competitivos; Los lenguajes compilados fuertemente tipados, donde pueden detectarse más defectos en el momento de la compilación, son menos propensos a fallas en tiempo de ejecución que los lenguajes interpretados o débilmente tipados. Discutimos las implicaciones de estos resultados para desarrolladores, diseñadores de idiomas y educadores. donde se pueden detectar más defectos en el momento de la compilación, son menos propensos a fallas en el tiempo de ejecución que los lenguajes interpretados o de tipo débil. Discutimos las implicaciones de estos resultados para desarrolladores, diseñadores de idiomas y educadores. donde se pueden detectar más defectos en el momento de la compilación, son menos propensos a fallas en el tiempo de ejecución que los lenguajes interpretados o de tipo débil. Discutimos las implicaciones de estos resultados para desarrolladores, diseñadores de idiomas y educadores.


0

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 Pythony 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 Ccompilador versus Intel Ccompilador. (Busque el punto de referencia del compilador)


2
Si desea hacer comentarios sobre la pregunta, utilice el cuadro de comentarios, no su respuesta. Tenga en cuenta que esto es Computer Science Stack Exchange y la informática no es programación, así como la literatura no es procesamiento de textos. Preguntas de programación en vivo en Ingeniería de software o Desbordamiento de pila .
David Richerby
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.