20

He diseñado alrededor de 5 idiomas experimentales e intérpretes para ellos hasta ahora, para educación, como hobby y para diversión.Idiomas interpretados: ¿el nivel más alto es el más rápido?

Una cosa que noté: el lenguaje parecido a un ensamblaje que presentaba solo subrutinas y saltos condicionales como estructuras era mucho más lento que el lenguaje de alto nivel con if, while y demás. Los desarrollé a la vez y ambos fueron idiomas interpretados. Escribí los intérpretes en C++ e intenté optimizar la parte de ejecución del código para que fuera lo más rápido posible.

Mi hipótesis: en casi todos los casos, el rendimiento de los idiomas interpretados aumenta con su nivel (alto/bajo).

  • ¿Básicamente estoy de acuerdo con esto?

EDITAR (Si no es así, ¿por qué?): No he mencionado la palabra compilado aquí ni una sola vez, se trata de interpretar frente interpretado!

+13

Vaya, tanta gente NO leyó la pregunta aquí? Sheesh. OP no está comparando interpretado a lenguajes compilados. OP está comparando lenguajes interpretados de alto nivel con lenguajes INTERPRETADOS de bajo nivel ... –

+2

@Brian: Como se evidencia en la discusión a continuación, la distinción entre * compilado * y * interpretado * aparentemente no es tan claro como podría parecer a primera vista . –

+0

@Robert: ¿Cómo es eso? Un lenguaje compilado es un lenguaje que se compila en el ensamblaje de la máquina en la que se ejecutará. un lenguaje interpretado es un lenguaje que alimenta a un intérprete y se ejecuta en una especie de máquina virtual. Java no es ninguno de los dos. Java se traduce en un idioma intermedio que se interpreta. –

Respuesta

4

La realidad, por supuesto, es un poco más complicada que eso. A medida que los lenguajes, los intérpretes y los compiladores se vuelven más sofisticados, surgen nuevas oportunidades para que la máquina optimice el rendimiento. Además, el rendimiento de cualquier programa depende en gran medida de la calidad del código que el programador ha escrito.

Además, el rendimiento afecta a diferentes tipos de programas de diferentes maneras. Las aplicaciones de línea de negocio, por ejemplo, casi siempre toman la mayor parte de su velocidad buscando datos desde una base de datos y enviándolos a través del cable, mientras que los programadores de juegos deben lidiar con un concepto de rendimiento completamente diferente, a saber, el de la tarjeta de video. tasas

Por lo tanto, la imagen de rendimiento no es tan simple como podría parecer.

+2

Vale la pena señalar que dice que su lenguaje interpretado de nivel superior es más rápido que su lenguaje * interpretado * de menor nivel, * no * que es más rápido que el código compilado. Si bien los puntos que usted hace son perfectamente válidos, no creo que eso sea lo que está sugiriendo. –

+0

@ Adam: Sí, lo vi. ¿Quién oyó hablar de un * lenguaje ensamblado interpretado? * –

+0

@Robert Harvey: Necesitaba algo fácil para empezar; D Es bastante rápido, sin embargo: ** Tres veces más rápido que Python **, y 5 veces más rápido que Ruby. (Medido con varias llamadas de función, recursión, procesamiento de enteros y pruebas de manipulación de cadenas) – immersion

30

En ambos casos está interpetando el código. Me imagino que en los idiomas de nivel superior tienes menos instrucciones para lograr la misma tarea, por lo que pasas menos tiempo interpretando las instrucciones y más tiempo haciendo algo útil.

+1

Sugeriría que la interpretación del perfil OP de uno de sus altos niveles y uno de sus idiomas de bajo nivel. Si este es el motivo (probable), debe aparecer claramente en el perfil. –

+0

@Martinho: Yo lograría lo mismo con solo un paso del intérprete. Puedo decir cuánto tiempo está perdiendo por lo cansado que estoy. –

+0

@Mike: eso es exactamente lo que dije. Acabas de comprar un generador de perfiles que tienes que pedalear: P –

0

Resumen: la evaluación comparativa es difícil. No se puede generalizar a partir de anécdotas.

Esto no es una regla respaldada por evidencia.

¿Cómo está configurando su experimento del que saca la conclusión de "más alto = más rápido"? ¿Tiene ejemplos de implementaciones de algoritmos y conjuntos de pruebas idénticos que le permiten medir objetivamente un idioma interpretado frente a otro?

Si solo está creando pequeños mini-benchmarks, la probabilidad es muy alta de que esté sacando una conclusión de muy pocos puntos de datos.

Por ejemplo, si un idioma interpretado tiene un operador quicksort, puede pensar "¡Aha! ¡Más rápido!" que un lenguaje donde tienes que implementar la clasificación a mano. Sin embargo, quicksort tiene el peor rendimiento de O (n^2). Si entrego a su operación de nivel superior un ejemplo de un conjunto de datos del peor de los casos, un merge sort implementado a mano diferente lo va a superar.

+0

Bueno, aún puede hacer la optimización con idiomas interpretados. Ejemplos: IronPython, IronRuby (y estoy seguro de que las implementaciones C también tienen sus propias optimizaciones). También puede "compilar sobre la marcha", de la misma manera que un compilador JIT lo hace con bytecode de Java o CIL. –

+1

Estos ejemplos se compilan en un código de bytes (y presumiblemente optimizado) y luego se interpreta el código de bytes. – Joel

+0

@Joel: No sigo. El código de bytes * es un lenguaje interpretado *, y * sufre una optimización * por parte del intérprete (también conocido como compilador JIT). Además, IronPython se beneficia de las optimizaciones proporcionadas por el DLR, como el almacenamiento en caché del sitio de llamada. –

1

Bueno, obviamente dependerá de cómo haya implementado los diferentes idiomas.

Me atrevería a suponer que se deben interpretar más instrucciones para hacer lo mismo en un lenguaje interpretado de nivel inferior, y va a haber una sobrecarga de tener que interpretar cada instrucción de bajo nivel en lugar de menos declaraciones de nivel superior.

12

Al final, analizar una línea de texto en su idioma tomará aproximadamente la misma cantidad de tiempo si estamos hablando de ensamblaje frente a The Next Big Thing Language (TNBL). Esto no es cierto en un sentido literal, pero es cierto en una forma de Turing-esque, Big-O-Notación.

Si se necesita (de nuevo, "más o menos") la misma cantidad de tiempo para determinar lo que esto significa:

mov $3, $4, $5 

como esto:

print "foo" 

... entonces imaginemos escribir Hola Mundo en nuestros dos idiomas. El intérprete ensamblador va a tener un programa mucho más complejo para analizar. Diga, n líneas de largo, que es n veces tantas líneas como el Hello Wolrld de TNBL. Por lo tanto, su sobrecarga básica es n veces más larga.

Además de eso, tiene todo el código que ejecuta en el lenguaje más simple que modela el comportamiento de registros, operaciones, etc. Es mucho trabajo. En TNBL, hay casi una correspondencia de uno a uno entre la semántica del código interpretado y algo que puede hacer en el lenguaje de host. Esto significa una sobrecarga muy reducida al pasar de la semántica a la ejecución.

Estoy seguro de que verán algunos programadores de Java que rechazarían esta tesis, pero señalaría que Java tiene un par de ventajas: un bytecode intermedio que intenta obtener el código lo más cerca posible de el hardware como sea posible antes de ejecutarlo, y miles de años-hombre invertidos en el desarrollo de tiempo de compilación y optimización de tiempo de ejecución de ese lenguaje. Apenas están en el continuo con un lenguaje de aficionado. =]

1

Yo diría que tienes la mitad de razón. Si representó la velocidad de interpretación, con el nivel de idioma en el eje X y la velocidad de ejecución en el eje Y, obtendría una curva de "bañera": interpretar un lenguaje de nivel extremadamente bajo puede ser bastante rápido e interpretar un nivel extremadamente alto. el lenguaje de nivel puede ser bastante rápido. Entre los dos, la interpretación es sustancialmente más lenta.

Dado un lenguaje de entrada de nivel extremadamente alto (por ejemplo, APL), obtiene una sobrecarga de interpretación mínima porque puede hacer una gran cantidad de trabajo basándose en analizar relativamente poco código de entrada.

En el extremo opuesto, puede obtener una velocidad bastante decente simplemente porque con un lenguaje de bajo nivel, la interpretación se vuelve casi trivial. El intérprete interno de una implementación Forth es un excelente ejemplo de esto. Estos a menudo representan un programa dado bastante compacto, que tiende a ser bastante caché, por lo que al menos en teoría se puede ejecutar tan rápido como (o incluso algo más rápido que) el código de máquina puro.

La intención original era que la mayoría de las JVM, el entorno "administrado" de .NET, los intérpretes de código de bytes Smalltalk, etc., encajarían en este último caso. Como la mayoría de los que han intentado desarrollar esto lo han encontrado rápidamente, es difícil para mantener la interpretación lo suficientemente baja como para lograr esto. Todos los que conozco que encajan en esta clase tienen el bucle interno escrito en lenguaje ensamblador a mano y generalmente por un buen programador de lenguaje ensamblador.Casi iría tan lejos como para decir que si intentas usar un lenguaje de nivel superior (incluso C) va a ser más lento, y probablemente de manera significativa (cuando agregas una sobrecarga para cada instrucción de entrada, incluso una instrucción extra en el circuito interno conducirá casi con certeza a una penalización de velocidad mensurable).

0

¿Cómo se hace una comparación justa?

Supongo que no está contando la velocidad de análisis, y supongo que está generando un conjunto de instrucciones de código de bytes intermedio, y eso es lo que interpreta.

Supongamos que tiene un "punto de referencia" que es un ciclo para sumar los elementos de una matriz. Si su lenguaje de nivel superior tiene instrucciones especiales de código de bytes para esto, de modo que en el lenguaje de nivel superior, haya menos códigos de bytes para interpretar, eso explicaría por qué es más rápido.

0

Suponiendo que ambos se implementan aproximadamente de la misma manera, con el lenguaje de bajo nivel sin optimizar, y el lenguaje de alto nivel no expandido a un código intermedio de nivel inferior - 'probablemente'.

En tal caso, el lenguaje de alto nivel tendría la ventaja de incluir más código compilado (más rápido) por instrucción.

En la práctica, un lenguaje interpretado de bajo nivel debería ser capaz de reducir la sobrecarga por instrucción, y suele ser mucho más sencillo implementar la compilación JIT. Lo bien que se implemente cada uno determinará finalmente cómo se comparan entre sí.

Diré que es más fácil para implementar un lenguaje de alto nivel más rápido. (en mi experiencia limitada)

1

Si tenía un lenguaje interpretado con un comando: runMyEntireProgramNatively(), sería más rápido que un idioma interpretado con más comandos. Cuanto menos haga cada comando, mayor será la relación entre el tiempo invertido en la interpretación y el hecho de hacer las cosas.

Cuestiones relacionadas