Warum sind CIL und CLR in .NET erforderlich?

11

Ich habe dieses schöne Bild hier gesehen . Ich habe erfahren, dass alle Compiler, die die .net-Sprache unterstützen, den Quellcode in das CILFormat konvertieren. Jetzt bringt Microsoft niemals das .NETgesamte Betriebssystem ein, indem es eine CLR für alle Betriebssysteme schreibt. Warum sollten Sie dann ein solches Zwischencodeformat und eine CLR beibehalten, um diese CIL auszuführen? Ist das nicht Kopfschmerzen zu behandeln. Warum hat Microsoft so gewählt?

BEARBEITEN Diese Art von Architektur hat ihren Preis. Es wird die Leistung reduzieren, nicht wahr? Java tut dies, um die Plattformunabhängigkeit aufrechtzuerhalten. Aus welchem ​​Grund tut .NET dies? Warum nicht einen einfachen C-ähnlichen Compiler behalten? In jedem Fall muss ein Compiler den Code in CIL konvertieren, wenn ich eine neue Sprache hinzufügen muss. Der einzige Unterschied wäre die Zielsprache. Tat ist alles.

Vikkyhacks
quelle
3
Weil es einfacher ist, Compiler in CIL zu schreiben. Und es ist einfacher, eine CIL in den nativen Compiler zu schreiben, als einen Compiler in jede Sprache in den nativen Compiler.
Oded
9
@ratchetfreak: Dies mag ein Grund für MS sein, die CLR nicht auf andere Plattformen zu portieren, aber es ist kein Grund, überhaupt eine CLR zu haben (was einen Port tatsächlich einfacher macht , sodass Ihr Argument genau wie MS-Bashing klingt). Entschuldigung)
Doc Brown
12
Auch Downvote für 'M $', was ist das, 1998?
Alan B
3
Eric Lippert diskutiert dies (beginnend mit dem 3. Absatz; die ersten beiden Absätze handeln von Roslyn). Die kurze Antwort ist, dass Odeds Kommentar und Telastyns Antwort richtig sind; Sie müssen nur die Compiler <Anzahl der Betriebssysteme> + <Anzahl der Sprachen> anstelle der Compiler <Anzahl der Betriebssysteme> * <Anzahl der Sprachen> codieren.
Brian
3
@busy_wait: Auf der Seite, auf die verwiesen wird, werden einige Nachteile erwähnt. Beispiel: "Die Konfigurationsinformationen in zwei Anwendungen können zu unterschiedlichen Bindungsentscheidungen für dieselbe abhängige Assembly führen." Das schnelle Generieren vermeidet diese Probleme. Dies bedeutet, dass die Kompilierung wirklich nach der Verteilung der App durchgeführt werden muss (und tatsächlich muss NGEN auf jedem Zielcomputer ausgeführt werden; es kann nicht vom Verteiler ausgeführt werden).
Brian

Antworten:

29

Weil sie nur einen Compiler für C # in CIL schreiben müssen - was der schwierige Teil ist. Das Erstellen eines Interpreters (oder häufiger eines Just-In-Time-Compilers) für die CIL pro Plattform ist relativ einfach im Vergleich zum Schreiben eines Compilers von C # in (pro Plattform) ausführbaren Code.

Darüber hinaus kann die Laufzeit alles verarbeiten, was zu CIL kompiliert wird. Wenn Sie eine neue Sprache (wie F #) möchten, müssen Sie nur einen Compiler dafür schreiben , und Sie erhalten automatisch die gesamte Plattformunterstützung für Dinge, die .NET unterstützt.

Oh, und ich kann eine .NET-DLL nehmen und diese unter Windows oder Linux über Mono ohne Neukompilierung ausführen (vorausgesetzt, alle meine Abhängigkeiten sind erfüllt).

Die Leistung ist umstritten. Es gibt im Wesentlichen "Pre-Compiler", die die CIL verwenden und native Binärdateien erstellen. Andere argumentieren, dass Just-in-Time-Compiler Optimierungen vornehmen können, die statische Compiler einfach nicht können. Nach meiner Erfahrung hängt es stark davon ab, was Ihre Anwendung tut und auf welcher Plattform Sie sie ausführen (hauptsächlich, wie gut der JITer auf dieser Plattform ist). Es ist äußerst selten, dass ich auf ein Szenario stoße, in dem .NET nicht gut genug war .

Telastyn
quelle
"Dolmetscher" `? Ich dachte immer MS bietet nur einen JITter?
Doc Brown
1
@ DocBrown - eh, ja - Fehlbezeichnung meinerseits. Festsetzung.
Telastyn
+1, können Sie ein wenig Erklärung für meine Bearbeitung hinzufügen, damit ich diese Antwort akzeptieren kann
Vikkyhacks
Hochleistungslaufzeiten kombinieren häufig einen Interpreter und einen JIT-Compiler (Mixed-Mode-Ausführung). Ich bin mir bei .NET nicht sicher, aber viele Java-VMs verwenden diesen Ansatz.
Cyanfish
2
@busy_wait: Alle möglichen Dinge. Inlining von Methoden, Weitergabe von Kopien, Entfernen von unnötigem Code, Konvertieren von Multiplikationen / Divisionen in Verschiebungen, andere arithmetische Operationen unter Verwendung von readonlyFeldern. Herkömmliche Compiler können einige dieser Optimierungen durchführen, jedoch nur, wenn sie durch statische Analyse erkannt werden können. Im Gegensatz dazu kann ein Jitter zur Laufzeit feststellen, dass (zum Beispiel) ein Codeabschnitt keine nützliche Arbeit leistet, da die von ihm geänderten Objekte oder Variablen nirgendwo anders referenziert werden. Ich bin kein Experte für Jitter, aber es ist im Grunde eine Frage der Kraft der dynamischen vs. statischen Analyse.
Aaronaught
14

.NET verfügt aus dem gleichen Grund wie Java über eine Zwischensprache (CIL / MSIL) und plattformspezifische Implementierungen einer plattformunabhängigen Laufzeit (CLR). Microsoft beabsichtigte, C # direkt mit Java zu konkurrieren, und zwar auf den Betriebssystemen, auf die Microsoft abzielt (seine eigenen).

Die Vorteile sind ähnlich wie bei Java, obwohl .NET nur auf Windows-Plattformen (oder anderen Betriebssystemen mit .NET-ähnlichen Funktionen wie Mono / Linux) unterstützt wird:

  • Managed Memory Runtime - Im Gegensatz zu nicht verwaltetem C / C ++ müssen sich C # / VB.NET-Entwickler nicht um die strikte Kontrolle der Objektlebensdauer kümmern. Wie Java verfügt auch die CLR über einen Garbage Collector, der automatisch Objekte im Heap freigibt, die den Gültigkeitsbereich verlassen. Während dies für jemanden, der an nicht verwaltete Laufzeiten gewöhnt ist, unbedeutend erscheint, hat es den äußersten sekundären Vorteil, die in C / C ++ so übliche "schwarze Magie" der Zeigerarithmetik zu entmutigen.
  • Plattformunabhängigkeit - Windows Vista und Windows 7 funktionieren anders als Windows XP. Windows 8 funktioniert immer noch anders. Windows Mobile-Versionen einschließlich Windows 8 Mobile funktionieren wieder anders. Unterschiedliche Hardware, unterschiedliche Architektur, unterschiedliche Funktionen. Während die Zielumgebung für einen .NET-Entwickler immer noch von Bedeutung ist, ist der Umfang des Fachwissens im Vergleich zu dem, was bekannt sein muss, um ein kompatibles C / C ++ - Programm für alle diese Betriebssysteme zu erstellen, erheblich reduziert. AC # dev bekommt viel mehr kostenlos.
  • Unterstützung von Webanwendungen - Ich habe noch keine Client-bezogene Webanwendung mit Serverskript gesehen, die von Grund auf in C ++ geschrieben wurde. Der Web - Server , sicher, Apache, ISS, sie alle in der Regel laufen gegen eine nicht verwaltete Laufzeit für Geschwindigkeit / Effizienzgründen. C ++ ist jedoch keine Sprache zum Erstellen von Webanwendungen. C # ist (wie auch Java). Es wurde von Grund auf entwickelt, um die nächste Generation des ASP-Paradigmas von Microsoft zu unterstützen. Dies ist Code, der für die Ausführung in einer Sandbox entwickelt wurde. Welche Sandbox (das ASP.NET-Plugin für ISS oder die "Desktop" -CLR) ist relativ unwichtig.
  • Sprach- / Laufzeitunabhängigkeit - Ein C ++ - Compiler verwendet C ++ - Quellcode und erstellt Assembler-Code für eine Prozessorarchitektur unter Verwendung einer Maschinensprache. Um eine andere Architektur und / oder Maschinensprache zu unterstützen, muss ein völlig neuer Compiler geschrieben werden (und ein völlig neuer Satz von Laufzeitbibliotheken muss kompiliert werden). Der AC # -Compiler verwendet C # -Quellcode und erzeugt CIL, das der hardwarespezifische JITer in Maschinencode übersetzt. Der gleiche JITer kann jedes CIL-Programm unabhängig von der Ausgangssprache übersetzen (und es gibt mehrere; C #, VB.NET, F # und eine Vielzahl von "Iron" -Sprachenports wie IronHaskell, IronRuby, IronLisp usw.). Der gleiche Compiler kann eine Sprache in CIL umwandeln, die jeder JITer ausführen kann, unabhängig von der Hardware.
  • Konzentrieren Sie sich auf "richtigen" Code - Für C ++ - Entwickler gibt es viele "richtige" Möglichkeiten, etwas zu tun, je nachdem, was am wichtigsten ist. Speichereffizienz, CPU-Effizienz, Hardwareunabhängigkeit, Betriebssystemunabhängigkeit usw. Code kann drastisch anders aussehen, wenn jede dieser Prioritäten Priorität hat. C # wurde von einer Gruppe entworfen, die sich die konzeptionellen Lehren von Fowler und seinen Kollegen zu Herzen nahm (die daran arbeiteten, das Code-Design innerhalb der C ++ - Community zu reformieren, indem sie einer Community objektorientierte Prinzipien beibrachten, die sich weitgehend von C nach oben bewegte) sowie die praktischen Lektionen, die die vorhergehenden Sprachen gelernt haben (einschließlich Java und sein fast fanatischer Gehorsam gegenüber dem allmächtigen Objekt, wenn ein guter alter Funktionszeiger im C ++ - Stil die Arbeit viel sauberer erledigen und nicht weniger objektiv sein würde). orientiert).

Aus kartellrechtlichen Gründen achtet MS darauf, dass andere wichtige Plattformen wie Android, Mac OSX / iOS und Linux nicht zu stark "gestört" werden. Es gibt jedoch tatsächlich Teams, die sich für alle drei dieser Plattformen entwickeln. Es gibt eine von MS entwickelte Version von Office für OSX, es gibt zahlreiche Anwendungen, einschließlich Office Interop-Apps für iOS und Android, Skype (jetzt ein Microsoft-Produkt) läuft unter Linux, und Microsoft hat sogar einen Beitrag zum Linux-Kernel geleistet (hauptsächlich in a Virtualisierungs-Denkweise).

KeithS
quelle
1
"Ich habe noch keine Client-bezogene Webanwendung mit Serverskript gesehen, die von Grund auf in C ++ geschrieben wurde." - Wo platzieren Sie CGIs von alten Tagen? Meine allerersten Webanwendungen (so trivial sie auch waren) waren 100% C. Damals (Mitte der 90er Jahre) war es einfacher, ein .c und .h zu schreiben, um die Standardarbeit in CGI zu erledigen (die Skriptsprachen waren gerecht auch in der Szene auftauchen).
hm ... CGI, CGI ... Ich glaube, ich habe davon gehört, aber ich bin bei KeithS, ich muss noch einen sehen :)
DXM
@DXM Das alte Modell für dynamischen Inhalt war, dass der Webserver einen Prozess gabelte und Dinge an Standardorten platzierte (Abfrageparameter und dergleichen gingen in bestimmte Umgebungsvariablen) - die Common Gateway-Schnittstelle. Die Ausgabe dieses Prozesses wurde dann als Inhalt zurückgesendet. Früher war es einfacher, einen Programmierer zu finden, der C oder C ++ kannte, als Perl oder Python (und sh war für solche Arbeiten sehr klobig).
1
Unterschätzen Sie nicht die Bedeutung der Ähnlichkeit mit Java. Sun hatte gerade MS wegen ihres Hafens der JVM verklagt und einige rechtliche Punkte gewonnen (dumm, IMHO). CIL und die CLR sind davon inspiriert, und Sie werden feststellen, dass J # Java so nahe wie möglich kommt, ohne weitere rechtliche Schritte auszulösen. Ein großer Unterschied ist, dass die CLR sprachunabhängig ist. Sie können wirklich ein Programm in einer Mischung aus C #, F # und J # schreiben, wenn dies erforderlich ist. Versuchen Sie einfach, Java mit Bibliotheken in anderen Sprachen zu mischen und ein stabiles Programm zu erhalten.
RBerteig
1
Die Interop zwischen MSIL und nativem Code ist jedoch ziemlich gut definiert und funktioniert einfach. Und anscheinend sollte es nur nach Design und nach den Einstellungen der Benutzergemeinschaft funktionieren.
RBerteig
12

Das Windows-Betriebssystem ist für verschiedene CPU-Typen verfügbar, heute hauptsächlich x64, x86, Intel, ARM.

CIL / CLR ist unabhängig von dieser Hardwareplattform - diese Unterschiede werden von der IL-Ausführungsumgebung "abstrahiert". Beispielsweise kann eine für "jede CPU" kompilierte .NET-Assembly normalerweise unter Win64 als 64-Bit-Prozess und unter Win32 als 32-Bit-Prozess ausgeführt werden, ohne dass unterschiedliche ausführbare Dateien bereitgestellt werden müssen.

Darüber hinaus ermöglicht die CIL das Speichern von Metadaten in Assemblys, was mit nativen DLLs nicht einfach möglich ist (es ist natürlich möglich, dass MS dies zuvor mit COM-Komponenten getan hat, aber diese Technologie war nie so einfach zu handhaben wie .NET-Komponenten). Das macht die Erstellung von Softwarekomponenten um einiges einfacher und ist die Grundlage für Reflexion / Selbstbeobachtung in allen .NET-Sprachen.

Doc Brown
quelle
Um dies ein wenig hinzuzufügen, erlauben sie nicht nur unterschiedliche CPU-Typen, sondern auch unterschiedliche Versionen (Core i3 / i5 / i7) und Anbieter (Intel vs. AMD) innerhalb desselben CPU-Typs (z. B. alle x64) können unterschiedliche haben Sätze von Montageanweisungen, die der JIT-Compiler nutzen könnte
DXM
2
@ DXM: Und Sie wissen, dass die JIT tatsächlich tut? Oder ist das eher eine hypothetische Sache?
Doc Brown
Zumindest ein MSDN-Blog behauptet, dass der JIT-Compiler dies tut (oder dies vor 8 Jahren getan hat).
@DocBrown: Natürlich habe ich kein Referenzmaterial zur Hand, aber ich dachte, ich erinnere mich daran, dass ich vor langer Zeit etwas darüber gelesen habe. Danke delnan, dass du den Link gefunden hast. Dies wäre sinnvoll, da wir wissen, dass Chiphersteller ihre eigenen Anweisungen gerne zusätzlich zum Standard x86-x64 hinzufügen. Wenn die Maschine also die Vorteile nutzen kann, warum nicht?
DXM