java - pinecone - Lenguas compiladas vs. interpretadas
make a programming language in java (11)
Comience a pensar en términos de una: explosión del pasado
Érase una vez, hace mucho tiempo, vivía en la tierra de los intérpretes y compiladores informáticos. Todo tipo de alboroto se produjo sobre los méritos de uno sobre el otro. La opinión general en ese momento era algo así como:
- Intérprete: rápido de desarrollar (editar y ejecutar). Lento de ejecutar porque cada instrucción tuvo que interpretarse en código de máquina cada vez que se ejecutaba (piense en lo que esto significaba para un bucle ejecutado miles de veces).
- Compilador: lento de desarrollar (edite, compile, enlace y ejecute. Los pasos de compilación / enlace podrían tomar mucho tiempo). Rápido de ejecutar. Todo el programa ya estaba en código de máquina nativo.
Una diferencia de uno o dos órdenes de magnitud en el rendimiento en tiempo de ejecución existía entre un programa interpretado y un programa compilado. Otros puntos distintivos, por ejemplo, la mutabilidad en tiempo de ejecución del código, también fueron de algún interés, pero la distinción principal giró en torno a los problemas de rendimiento en tiempo de ejecución.
Hoy en día, el paisaje ha evolucionado hasta tal punto que la distinción compilada / interpretada es bastante irrelevante. Muchos lenguajes compilados recurren a servicios en tiempo de ejecución que no están completamente basados en código de máquina. Además, la mayoría de los idiomas interpretados se "compilan" en un código de bytes antes de la ejecución. Los intérpretes de código de bytes pueden ser muy eficientes y compiten con algunos códigos generados por compiladores desde un punto de vista de velocidad de ejecución.
La diferencia clásica es que los compiladores generaron código de máquina nativo, los intérpretes leen el código fuente y el código de máquina generado sobre la marcha utilizando algún tipo de sistema de tiempo de ejecución. Hoy quedan muy pocos intérpretes clásicos, casi todos compilados en código de bytes (o algún otro estado semi-compilado) que luego se ejecuta en una "máquina" virtual.
Estoy tratando de entender mejor la diferencia. He encontrado muchas explicaciones en línea, pero tienden a las diferencias abstractas más que a las implicaciones prácticas.
La mayoría de mis experiencias de programación han sido con CPython (dinámico, interpretado) y Java (estático, compilado). Sin embargo, entiendo que hay otros tipos de lenguajes interpretados y compilados. Aparte del hecho de que los archivos ejecutables pueden distribuirse desde programas escritos en lenguajes compilados, ¿existen ventajas / desventajas para cada tipo? A menudo, escucho a personas argumentando que los lenguajes interpretados pueden usarse interactivamente, pero creo que los lenguajes compilados también pueden tener implementaciones interactivas, ¿correcto?
Compilar es el proceso de crear un programa ejecutable a partir de un código escrito en un lenguaje de programación compilado. La compilación permite que la computadora ejecute y entienda el programa sin la necesidad del software de programación utilizado para crearlo. Cuando se compila un programa, a menudo se compila para una plataforma específica (por ejemplo, la plataforma de IBM) que funciona con computadoras compatibles con IBM, pero no con otras plataformas (por ejemplo, la plataforma de Apple). El primer compilador fue desarrollado por Grace Hopper mientras trabajaba en la computadora Harvard Mark I. Hoy en día, la mayoría de los lenguajes de alto nivel incluirán su propio compilador o tendrán disponibles kits de herramientas que se pueden usar para compilar el programa. Un buen ejemplo de un compilador usado con Java es Eclipse y un ejemplo de un compilador usado con C y C ++ es el comando gcc. Dependiendo de qué tan grande sea el programa, debería tardar unos segundos o minutos en compilarse y, si no se encuentran errores al compilarse, se crea un archivo ejecutable. Verifique esta información
De http://www.quora.com/What-is-the-difference-between-compiled-and-interpreted-programming-languages
No hay diferencia, porque "lenguaje de programación compilado" y "lenguaje de programación interpretado" no son conceptos significativos. Cualquier lenguaje de programación, y realmente me refiero a cualquiera, puede ser interpretado o compilado. Así, la interpretación y la compilación son técnicas de implementación, no atributos de lenguajes.
La interpretación es una técnica mediante la cual otro programa, el intérprete, realiza operaciones en nombre del programa que se está interpretando para ejecutarlo. Si puede imaginar leer un programa y hacer lo que se dice hacer paso a paso, digamos en un papel de borrador, eso es lo que hace un intérprete también. Una razón común para interpretar un programa es que los intérpretes son relativamente fáciles de escribir. Otra razón es que un intérprete puede monitorear lo que un programa intenta hacer mientras se ejecuta, para hacer cumplir una política, por ejemplo, por seguridad.
La compilación es una técnica mediante la cual un programa escrito en un idioma (el "idioma de origen") se traduce a un programa en otro idioma (el "lenguaje de objetos"), que se espera que signifique lo mismo que el programa original. Al realizar la traducción, es común que el compilador también intente transformar el programa de manera que el programa objeto sea más rápido (¡sin cambiar su significado!). Una razón común para compilar un programa es que hay una buena manera de ejecutar programas en el lenguaje de objetos rápidamente y sin la sobrecarga de interpretar el idioma de origen en el camino.
Es posible que, según las definiciones anteriores, haya adivinado que estas dos técnicas de implementación no se excluyen mutuamente e incluso pueden ser complementarias. Tradicionalmente, el lenguaje de objeto de un compilador era un código de máquina o algo similar, que se refiere a cualquier número de lenguajes de programación entendidos por CPU de computadora en particular. El código de la máquina luego se ejecutaría "en el metal" (aunque uno podría ver, si se mira lo suficientemente de cerca, que el "metal" se parece mucho a un intérprete). Sin embargo, hoy en día, es muy común usar un compilador para generar código objeto que debe interpretarse; por ejemplo, así es como Java solía (ya veces todavía funciona) el trabajo. Hay compiladores que traducen otros idiomas a JavaScript, que a menudo se ejecuta en un navegador web, que puede interpretar el JavaScript, o compilarlo en una máquina virtual o código nativo. También tenemos intérpretes para el código de máquina, que se pueden usar para emular un tipo de hardware en otro. O, uno podría usar un compilador para generar código objeto que luego es el código fuente de otro compilador, que incluso podría compilar código en la memoria justo a tiempo para que se ejecute, que a su vez. . . tienes la idea Hay muchas maneras de combinar estos conceptos.
El libro de Python © 2015 Imagine Publishing Ltd, simplemente distingue la diferencia con el siguiente indicio que se menciona en la página 10 como:
Un lenguaje interpretado como Python es uno donde el código fuente se convierte en código de máquina y luego se ejecuta cada vez que se ejecuta el programa. Esto es diferente de un lenguaje compilado como C, donde el código fuente solo se convierte a código de máquina una vez; el código de máquina resultante se ejecuta cada vez que se ejecuta el programa.
Es bastante difícil dar una respuesta práctica porque la diferencia está en la definición del lenguaje en sí. Es posible crear un intérprete para cada lenguaje compilado, pero no es posible compilar un compilador para cada idioma interpretado. Se trata mucho de la definición formal de un lenguaje. Así que esa informática teórica no le gusta a nadie en la universidad.
La mayor ventaja del código fuente interpretado sobre el código fuente compilado es la portabilidad .
Si su código fuente está compilado, necesita compilar un ejecutable diferente para cada tipo de procesador y / o plataforma en que desea que se ejecute su programa (por ejemplo, uno para Windows x86, uno para Windows x64, uno para Linux x64, etc.). en). Además, a menos que su código sea completamente compatible con los estándares y no use ninguna biblioteca / función específica de la plataforma, ¡realmente necesitará escribir y mantener múltiples bases de código!
Si su código fuente es interpretado, solo necesita escribirlo una vez y puede ser interpretado y ejecutado por un intérprete apropiado en cualquier plataforma. ¡Es portátil ! Tenga en cuenta que un intérprete en sí es un programa ejecutable que se escribe y compila para una plataforma específica.
Una ventaja del código compilado es que oculta el código fuente al usuario final (que podría ser propiedad intelectual ) porque en lugar de implementar el código fuente original legible, se implementa un archivo ejecutable binario oscuro.
Los casos extremos y simples:
Un compilador producirá un ejecutable binario en el formato ejecutable nativo de la máquina de destino. Este archivo binario contiene todos los recursos necesarios, excepto las bibliotecas del sistema; está listo para ejecutarse sin más preparación ni procesamiento, y funciona como un rayo porque el código es el código nativo de la CPU en la máquina de destino.
Un intérprete presentará al usuario un mensaje en un bucle donde puede ingresar instrucciones o código, y al pulsar
RUN
o el equivalente, el intérprete examinará, escaneará, analizará e interpretará cada línea hasta que el programa se ejecute hasta un punto de parada o un error. Debido a que cada línea se trata por sí sola y el intérprete no "aprende" nada de haber visto la línea antes, el esfuerzo de convertir el lenguaje legible por humanos en instrucciones de máquina se incurre cada vez en cada línea, por lo que es lento. En el lado positivo, el usuario puede inspeccionar e interactuar de otra manera con su programa en todo tipo de formas: cambio de variables, cambio de código, ejecución en modos de seguimiento o depuración ... lo que sea.
Con aquellos fuera del camino, déjenme explicarles que la vida ya no es tan simple. Por ejemplo,
- Muchos intérpretes compilarán previamente el código que se les da para que el paso de la traducción no tenga que repetirse una y otra vez.
- Algunos compiladores no compilan las instrucciones de la máquina específicas de la CPU, sino el código de bytes, un tipo de código de máquina artificial para una máquina ficticia. Esto hace que el programa compilado sea un poco más portátil, pero requiere un intérprete de código de bytes en cada sistema de destino.
- Los intérpretes de bytecode (estoy mirando Java aquí) recientemente tienden a volver a compilar el bytecode que obtienen para la CPU de la sección de destino justo antes de la ejecución (llamado JIT). Para ahorrar tiempo, a menudo esto solo se hace para el código que se ejecuta a menudo (hotspots).
- Algunos sistemas que se parecen y actúan como intérpretes (Clojure, por ejemplo) compilan cualquier código que obtienen de forma inmediata, pero permiten el acceso interactivo al entorno del programa. Eso es básicamente la conveniencia de los intérpretes con la velocidad de la compilación binaria.
- Algunos compiladores realmente no compilan, simplemente compilan previamente y comprimen el código. Oí hace un tiempo que así es como funciona Perl. Así que a veces el compilador simplemente hace un poco del trabajo y la mayor parte sigue siendo interpretación.
Al final, en estos días, la interpretación frente a la compilación es un compromiso, ya que el tiempo empleado (una vez) en la compilación suele ser recompensado por un mejor rendimiento en tiempo de ejecución, pero un entorno interpretativo que ofrece más oportunidades para la interacción. Compilar frente a interpretar es principalmente una cuestión de cómo el trabajo de "entender" el programa se divide entre diferentes procesos, y la línea está un poco borrosa en estos días, ya que los idiomas y los productos intentan ofrecer lo mejor de ambos mundos.
Primero, una aclaración, Java no está completamente compilado de forma estática y enlazado en la forma en que C ++. Se compila en el bytecode, que luego es interpretado por una JVM. La JVM puede ir y hacer la compilación justo a tiempo al lenguaje de máquina nativo, pero no tiene que hacerlo.
Más al punto: creo que la interactividad es la principal diferencia práctica. Dado que todo se interpreta, puede tomar un pequeño fragmento de código, analizarlo y ejecutarlo en relación con el estado actual del entorno. Por lo tanto, si ya había ejecutado código que inicializó una variable, tendría acceso a esa variable, etc. Realmente se presta a cosas como el estilo funcional.
Sin embargo, la interpretación cuesta mucho, especialmente cuando tiene un sistema grande con muchas referencias y contexto. Por definición, es un desperdicio porque el código idéntico puede tener que interpretarse y optimizarse dos veces (aunque la mayoría de los tiempos de ejecución tienen cierto almacenamiento en caché y optimizaciones para eso). Aún así, usted paga un costo de tiempo de ejecución y, a menudo, necesita un entorno de tiempo de ejecución. También es menos probable que vea optimizaciones complejas de interpretación porque en la actualidad su rendimiento no es lo suficientemente interactivo.
Por lo tanto, para los sistemas grandes que no van a cambiar mucho, y para ciertos idiomas, tiene más sentido precompilar y prelinkear todo, hacer todas las optimizaciones que pueda hacer. Esto termina con un tiempo de ejecución muy magro que ya está optimizado para la máquina de destino.
En cuanto a la generación de ejecutables, eso tiene poco que ver con eso, IMHO. A menudo puedes crear un ejecutable desde un lenguaje compilado. Pero también puede crear un ejecutable a partir de un lenguaje interpretado, excepto que el intérprete y el tiempo de ejecución ya están empaquetados en un valor exentable. Esto significa que, en general, todavía paga los costos de tiempo de ejecución (aunque estoy seguro de que para algún idioma hay formas de traducir todo a un árbol ejecutable).
No estoy de acuerdo en que todos los idiomas puedan ser interactivos. Ciertos idiomas, como C, están tan ligados a la máquina y a toda la estructura del enlace que no estoy seguro de que pueda crear una versión interactiva significativa y completa.
Un compilador y un intérprete hacen el mismo trabajo: traducir un lenguaje de programación a otro lenguaje pgoramming, generalmente más cercano al hardware, a menudo código de máquina ejecutable directo.
Tradicionalmente, "compilado" significa que esta traducción se realiza de una vez, la realiza un desarrollador y el ejecutable resultante se distribuye a los usuarios. Ejemplo puro: C ++. La compilación generalmente toma bastante tiempo y trata de hacer una gran cantidad de costosas opciones de modo que el ejecutable resultante se ejecute más rápido. Los usuarios finales no tienen las herramientas y el conocimiento para compilar cosas por sí mismos, y el ejecutable a menudo tiene que ejecutarse en una variedad de hardware, por lo que no puede hacer muchas optimizaciones específicas de hardware. Durante el desarrollo, el paso de compilación separado significa un ciclo de retroalimentación más largo.
Tradicionalmente, "interpretado" significa que la traducción se realiza "sobre la marcha", cuando el usuario desea ejecutar el programa. Ejemplo puro: PHP vainilla. Un intérprete ingenuo tiene que analizar y traducir cada pieza de código cada vez que se ejecuta, lo que lo hace muy lento. No puede realizar optimizaciones complejas y costosas porque llevaría más tiempo que el tiempo ahorrado en la ejecución. Pero puede utilizar completamente las capacidades del hardware en el que se ejecuta. La falta de un paso de compilación por separado reduce el tiempo de retroalimentación durante el desarrollo.
Pero hoy en día "compilado contra interpretado" no es un problema en blanco o negro, hay sombras en el medio. Intérpretes ingenuos y simples están prácticamente extintos. Muchos idiomas usan un proceso de dos pasos donde el código de alto nivel se traduce a un código de bytes independiente de la plataforma (que es mucho más rápido de interpretar). Luego tiene "compiladores justo a tiempo" que compilan código a lo sumo una vez por ejecución del programa, a veces resultados de caché, e incluso deciden inteligentemente interpretar el código que se ejecuta rara vez, y realizan optimizaciones poderosas para el código que se ejecuta mucho. Durante el desarrollo, los depuradores son capaces de cambiar el código dentro de un programa en ejecución incluso para lenguajes compilados tradicionalmente.
Un lenguaje compilado es uno donde el programa, una vez compilado, se expresa en las instrucciones de la máquina de destino. Por ejemplo, una operación "+" adicional en su código fuente podría traducirse directamente a la instrucción "AGREGAR" en el código de máquina.
Un lenguaje interpretado es uno donde las instrucciones no son ejecutadas directamente por la máquina de destino, sino que son leídas y ejecutadas por algún otro programa (que normalmente está escrito en el idioma de la máquina nativa). Por ejemplo, la misma operación "+" sería reconocida por el intérprete en el tiempo de ejecución, que luego llamaría a su propia función "agregar (a, b)" con los argumentos apropiados, que luego ejecutaría la instrucción "AGREGAR" del código de máquina .
Puede hacer cualquier cosa que pueda hacer en un lenguaje interpretado en un lenguaje compilado y viceversa, ambos son Turing completos. Sin embargo, ambos tienen ventajas y desventajas para la implementación y el uso.
Voy a generalizar completamente (¡los puristas me perdonan!) Pero, a grandes rasgos, aquí están las ventajas de los lenguajes compilados:
- Rendimiento más rápido utilizando directamente el código nativo de la máquina de destino
- Oportunidad de aplicar optimizaciones bastante potentes durante la etapa de compilación.
Y aquí están las ventajas de los lenguajes interpretados:
- ¡Más fácil de implementar (escribir buenos compiladores es muy difícil!)
- No es necesario ejecutar una etapa de compilación: puede ejecutar código directamente "sobre la marcha"
- Puede ser más conveniente para lenguajes dinámicos.
Tenga en cuenta que las técnicas modernas, como la compilación de códigos de bytes, agregan cierta complejidad adicional. Lo que sucede aquí es que el compilador apunta a una "máquina virtual" que no es lo mismo que el hardware subyacente. Estas instrucciones de la máquina virtual se pueden volver a compilar en una etapa posterior para obtener el código nativo (por ejemplo, como lo hizo el compilador JVM JIT de Java).
Un lenguaje en sí no es compilado ni interpretado, solo una implementación específica de un lenguaje es. Java es un ejemplo perfecto. Existe una plataforma basada en bytecode (la JVM), un compilador nativo (gcj) y un intérprete para un superconjunto de Java (bsh). Entonces, ¿qué es Java ahora? ¿Bytecode compilado, compilado nativo o interpretado?
Otros idiomas, que se compilan y se interpretan, son Scala, Haskell o Ocaml. Cada uno de estos idiomas tiene un intérprete interactivo, así como un compilador a código de byte o código de máquina nativo.
Así que, en general, categorizar idiomas por "compilado" e "interpretado" no tiene mucho sentido.