¿Por qué se requieren CIL y CLR en .NET?

11

Vi esta bonita imagen aquí . Aprendí que todos los compiladores que admiten el lenguaje .net convierten el código fuente al CILformato. Ahora Microsoft nunca está incorporando .NETtodo el sistema operativo escribiendo un CLR para todos los sistemas operativos. Entonces, ¿por qué mantener un formato de código intermedio y un CLR para ejecutar ese CIL? ¿No es un dolor de cabeza con el que lidiar? ¿Por qué Microsoft eligió ser así?

EDITAR Este tipo de arquitectura tiene su precio. Reducirá el rendimiento, ¿no? Java hace esto para mantener la independencia de la plataforma, ¿por qué razón lo hace .NET? ¿Por qué no mantener un simple compilador de C simple? Cualquier forma también requerirá un compilador para convertir el código a CIL si necesito agregar un nuevo idioma, la única diferencia que haría es el idioma de destino. Tat es todo.

vikkyhacks
fuente
3
Porque es más fácil escribir compiladores en CIL. Y es más fácil escribir un CIL en un compilador nativo que un compilador en todos y cada uno de los idiomas.
Oded
99
@ratchetfreak: esa puede ser una razón para MS para no portar el CLR a otras plataformas, pero no es una razón para tener un CLR en primer lugar (lo que en realidad hace que un puerto sea ​​más fácil , por lo que su argumento suena como MS bashing, lo siento)
Doc Brown
12
También voto negativo para 'M $', ¿qué es esto, 1998?
Alan B
3
Eric Lippert discute esto (comenzando en el tercer párrafo; los primeros 2 párrafos son sobre Roslyn). La respuesta corta es que el comentario de Oded y la respuesta de Telastyn son correctos; solo necesita codificar los compiladores <Número de sistemas operativos> + <Número de idiomas> en lugar de <Número de sistemas operativos> * <Número de idiomas> compiladores.
Brian
3
@busy_wait: la página referenciada menciona algunas desventajas. Por ejemplo, "la información de configuración en dos aplicaciones puede dar lugar a decisiones vinculantes diferentes para el mismo ensamblado dependiente". Generar sobre la marcha evita estos problemas. Esto implica que la compilación realmente debe hacerse después de que se distribuye la aplicación (y, de hecho, NGEN debe ejecutarse en cada máquina de destino; el distribuidor no puede ejecutarla).
Brian

Respuestas:

29

Porque solo necesitan escribir un compilador para C # a CIL, que es la parte difícil. Hacer un intérprete (o más a menudo, un compilador Just-In-Time) para el CIL por plataforma es relativamente fácil en comparación con escribir un compilador de C # a un código ejecutable (por plataforma).

Más allá de eso, el tiempo de ejecución puede manejar cualquier cosa que se compile a CIL. Si desea un nuevo lenguaje (como F #), solo tiene que escribir un compilador para él y automáticamente obtiene mágicamente todo el soporte de la plataforma para cosas que admite .NET.

Ah, y puedo tomar un .NET dll y ejecutarlo en Windows o en Linux a través de Mono sin recompilar (suponiendo que todas mis dependencias estén satisfechas).

En cuanto al rendimiento, es discutible. Hay "precompiladores" esencialmente que toman el CIL y hacen binarios nativos. Otros argumentan que los compiladores justo a tiempo pueden hacer optimizaciones que los compiladores estáticos simplemente no pueden hacer. En mi experiencia, depende mucho de lo que esté haciendo su aplicación y de la plataforma en la que la esté ejecutando (principalmente lo bueno que es el JITer en esa plataforma). Es extremadamente raro para mí encontrarme en un escenario donde .NET no sea lo suficientemente bueno .

Telastyn
fuente
"intérprete" Pensé que siempre MS solo proporciona un JITter?
Doc Brown
1
@DocBrown - eh, sí - nombre inapropiado de mi parte. Fijación.
Telastyn
1, se puede añadir un poco de explicación para mi edición para que pueda aceptar esta respuesta
vikkyhacks
Los tiempos de ejecución de alto rendimiento a menudo combinan un intérprete y un compilador JIT (ejecución en modo mixto). No estoy seguro acerca de .NET, pero muchas máquinas virtuales Java utilizan este enfoque.
Cyanfish
2
@busy_wait: Todo tipo de cosas. Método en línea, copia de propagación, eliminación de código innecesario, conversión de multiplicaciones / divisiones en turnos, otras operaciones aritméticas utilizando readonlycampos. Los compiladores tradicionales pueden hacer algunas de estas optimizaciones, pero solo cuando pueden detectarse mediante análisis estático. Por el contrario, un jitter puede descubrir en tiempo de ejecución que (por ejemplo) una sección de código no está haciendo ningún trabajo útil porque los objetos o variables que modifica no están referenciados en ningún otro lugar. No soy un experto en nerviosismo, pero se trata básicamente del poder del análisis dinámico frente al análisis estático.
Aaronaught
14

.NET tiene un lenguaje intermedio (CIL / MSIL) e implementaciones específicas de la plataforma de un tiempo de ejecución independiente de la plataforma (CLR) por la misma razón que Java. Microsoft pretendía que C # compitiera directamente con Java, y lo hace, en los sistemas operativos a los que se dirige Microsoft (el suyo).

Las ventajas, aunque .NET solo es compatible con plataformas Windows (u otros sistemas operativos que tienen un funcionamiento similar a .NET como Mono / Linux), son similares a Java:

  • Tiempo de ejecución de memoria administrada: a diferencia de C / C ++ no administrado, los desarrolladores de C # / VB.NET no tienen que preocuparse por controlar estrictamente la vida útil de los objetos. Al igual que Java, el CLR tiene un recolector de basura que libera automáticamente objetos en el montón que dejan alcance. Si bien esto puede parecer menor para alguien acostumbrado a tiempos de ejecución no administrados, tiene la ventaja secundaria extrema de desalentar la "magia negra" de la aritmética de puntero que es tan común en C / C ++.
  • Independencia de plataforma: Windows Vista y Windows 7 funcionan de manera diferente a Windows XP. Windows 8 funciona de manera diferente. Las versiones de Windows Mobile, incluido Windows 8 Mobile, funcionan de manera diferente nuevamente. Hardware diferente, arquitectura diferente, capacidades diferentes. Si bien el entorno de destino sigue siendo importante para un desarrollador .NET, la cantidad de conocimiento especializado se reduce mucho en comparación con lo que se debe saber para construir un programa C / C ++ compatible para todos estos sistemas operativos. AC # dev obtiene mucho más de forma gratuita.
  • Compatibilidad con aplicaciones web: todavía no he visto una aplicación web orientada al servidor orientada al cliente escrita desde cero en C ++. El servidor web , claro, Apache, ISS, generalmente se ejecutan contra un tiempo de ejecución no administrado por razones de velocidad / eficiencia. Sin embargo, C ++ no es un lenguaje utilizado para crear aplicaciones web. C # es (como es Java). Fue diseñado desde cero para admitir la próxima generación del paradigma ASP de Microsoft. Este es un código diseñado para ejecutarse en un sandbox; qué sandbox (el complemento ASP.NET para ISS o el CLR "de escritorio") es relativamente poco importante.
  • Independencia de lenguaje / tiempo de ejecución: un compilador de C ++ toma el código fuente de C ++ y produce código de ensamblaje para una arquitectura de procesador utilizando un lenguaje de máquina. Para admitir una arquitectura diferente y / o lenguaje de máquina, se debe escribir un compilador completamente nuevo (y se debe compilar un conjunto completamente nuevo de bibliotecas de tiempo de ejecución). El compilador AC # toma el código fuente de C # y produce CIL, que el JITer específico del hardware se traduce en código de máquina. El mismo JITer puede traducir cualquier programa CIL sin importar el idioma de origen (y hay varios; C #, VB.NET, F # y una gran cantidad de puertos de idioma "Iron" como IronHaskell, IronRuby, IronLisp, etc.). El mismo compilador puede convertir un idioma en CIL que cualquier JITer puede ejecutar, sin importar el hardware.
  • Concéntrese en el código "correcto": para los desarrolladores de C ++, hay muchas formas "correctas" de hacer algo, según lo más importante; eficiencia de memoria, eficiencia de CPU, independencia de hardware, independencia del sistema operativo, etc. El código puede verse drásticamente diferente cuando cada uno de estos es la prioridad. C # fue diseñado por un grupo que tomó en serio las lecciones conceptuales de Fowler y sus colegas (que estaban trabajando para reformar el diseño del código dentro de la comunidad C ++ al enseñar principios orientados a objetos a una comunidad que en gran medida pasó de C), como así como las lecciones prácticas aprendidas por los lenguajes anteriores (incluido Java, y su obediencia casi fanática al Objeto todopoderoso, cuando un buen puntero de función de estilo C ++ haría el trabajo de manera mucho más limpia y no sería menos objeto) orientado).

Por razones antimonopolio, MS tiene cuidado de no ser visto "interfiriendo" demasiado en otras plataformas importantes como Android, Mac OSX / iOS y Linux; sin embargo, sí tiene equipos en desarrollo para las tres plataformas. Hay una versión de Office para OSX desarrollada por MS, hay numerosas aplicaciones que incluyen aplicaciones de interoperabilidad de Office para iOS y Android, Skype (ahora un producto de Microsoft) se ejecuta en Linux e incluso se ha visto que Microsoft contribuye al kernel de Linux (principalmente en un mentalidad de virtualización).

KeithS
fuente
1
"Todavía no he visto una aplicación web con secuencias de comandos orientada al servidor escrita desde cero en C ++". - ¿Dónde pones los CGI de antaño? Mis primeras aplicaciones web (tan triviales como eran) fueron 100% C. En aquel entonces (mediados de los 90) era más fácil escribir un .cy .h para hacer el trabajo estándar en cgi (los lenguajes de 'scripting' eran simplemente emergente en la escena también).
hm ... CGI, CGI ... Creo que me enteré, pero estoy con KeithS, todavía no he visto uno :)
DXM
@DXM, el antiguo modelo de contenido dinámico era para el servidor web que bifurcaba un proceso y colocaba las cosas en lugares estándar (los parámetros de consulta y similares estaban en variables de entorno específicas): la Interfaz de puerta de enlace común. El resultado de ese proceso se devolvió como contenido. En los viejos tiempos, era más fácil encontrar un programador que conociera C o C ++ en lugar de perl o python (y sh era muy torpe para ese trabajo).
1
No subestimes la importancia de la similitud con Java. Sun acababa de demandar a MS por su puerto de la JVM y ganó algunos puntos legales (estúpidamente, en mi humilde opinión). CIL y CLR están inspirados en eso, y notará que J # está lo más cerca posible de Java sin desencadenar más acciones legales. Una gran diferencia es que el CLR es independiente del lenguaje. Realmente puede escribir un programa en una combinación de C #, F # y J # si eso es lo que se necesita. Simplemente intente mezclar Java con bibliotecas en otros idiomas y obtenga un programa estable.
RBerteig
1
Pero la interoperabilidad entre MSIL y el código nativo está razonablemente bien definida y simplemente funciona. Y aparentemente se esperaba que solo funcionara por diseño y por las actitudes de la comunidad de usuarios.
RBerteig
12

El sistema operativo Windows está disponible para diferentes tipos de CPU, actualmente principalmente x64, x86, Intel, ARM.

CIL / CLR es independiente de esa plataforma de hardware: el entorno de ejecución de IL "abstrae" estas diferencias. Por ejemplo, un ensamblado .NET compilado para "cualquier CPU" generalmente puede ejecutarse en Win64 como un proceso de 64 bits, y Win32 como un proceso de 32 bits, sin la necesidad de proporcionar diferentes ejecutables.

Además, el CIL permite que los metadatos se almacenen en ensamblajes que no es posible fácilmente con archivos DLL nativos (es posible, por supuesto, MS hizo esto antes con componentes COM, pero esa tecnología nunca fue tan fácil de manejar como los componentes .NET). Eso hace que la creación de componentes de software sea mucho más simple y es la base de la reflexión / introspección en todos los lenguajes .NET.

Doc Brown
fuente
Solo para agregar un poco a esto, no solo permiten diferentes tipos de CPU, sino que incluso diferentes versiones (Core i3 / i5 / i7) y proveedores (Intel vs. AMD) dentro del mismo tipo de CPU (todos x64, por ejemplo) pueden tener diferentes conjuntos de instrucciones de ensamblaje que el compilador JIT podría aprovechar
DXM
2
@DXM: ¿y sabes que el JIT lo hace en realidad? ¿O es esto más una cosa hipotética?
Doc Brown
Al menos un blog de MSDN afirma que el compilador JIT hace eso (o lo hizo, hace 8 años).
@DocBrown: Obviamente no tengo ningún material de referencia disponible, pero pensé que recordaba haber leído algo sobre esto hace mucho tiempo. Gracias, delnan, por encontrar el enlace. Tendría sentido ya que sabemos que a los fabricantes de chips les gusta agregar sus propias instrucciones además del estándar x86-x64, por lo que si la máquina puede aprovechar, ¿por qué no?
DXM