Dlaczego w .NET wymagane są CIL i CLR?

11

Widziałem tutaj ten ładny obraz . Dowiedziałem się, że wszystkie kompilatory obsługujące język .net konwertują kod źródłowy na CILformat. Teraz Microsoft nigdy nie wprowadza .NETcałego systemu operacyjnego, pisząc CLR dla wszystkich systemów operacyjnych. Dlaczego więc zachować taki pośredni format kodu i CLR, aby wykonać ten CIL. Czy to nie ból głowy? Dlaczego Microsoft tak wybrał?

EDYCJA Ten rodzaj architektury ma swoją cenę. Zmniejszy to wydajność, prawda? Java robi to, aby zachować niezależność platformy, z jakiego powodu .NET to robi? Dlaczego nie zachować prostego kompilatora typu C? Jakikolwiek sposób będzie wymagał również kompilatora do konwersji kodu na CIL, jeśli będę musiał dodać nowy język, jedyną różnicą, jaką by to zrobił, był język docelowy. Tat jest wszystkim.

Vikkyhacks
źródło
3
Ponieważ łatwiej jest pisać kompilatory w CIL. Łatwiej jest napisać jeden CIL do natywnego kompilatora niż kompilator do każdego języka na natywny.
Oded
9
@ratchetfreak: może to być powód, dla którego MS nie przenosi CLR na inne platformy, ale nie jest to powód do posiadania CLR w pierwszej kolejności (co w rzeczywistości ułatwia port , więc twój argument brzmi jak bash MS, przepraszam)
Doc Brown
12
Głosuj również na „M $”, co to jest, 1998?
Alan B,
3
Eric Lippert omawia to (począwszy od trzeciego akapitu; pierwsze 2 akapity dotyczą Roslyn). Krótka odpowiedź brzmi: komentarz Odeda i odpowiedź Telastyna są słuszne; wystarczy zakodować kompilatory <Liczba systemów operacyjnych> + <Liczba języków> zamiast <Liczba systemów operacyjnych> * <Liczba języków> kompilatory.
Brian
3
@busy_wait: strona, o której mowa, wspomina o kilku wadach. Na przykład „informacje o konfiguracji w dwóch aplikacjach mogą powodować różne decyzje dotyczące wiązania dla tego samego zestawu zależnego”. Generowanie w locie pozwala uniknąć tych problemów. Oznacza to, że kompilacja naprawdę musi zostać wykonana po rozpowszechnieniu aplikacji (w rzeczywistości NGEN musi być uruchomiony na każdej maszynie docelowej; nie może być uruchomiony przez dystrybutora).
Brian

Odpowiedzi:

29

Ponieważ muszą napisać tylko jeden kompilator dla C # do CIL - co jest trudną częścią. Utworzenie interpretera (lub częściej kompilatora Just-In-Time) dla CIL na platformę jest stosunkowo łatwe w porównaniu z pisaniem kompilatora z kodu C # na (na platformę) kod wykonywalny.

Poza tym środowisko wykonawcze może obsłużyć wszystko, co kompiluje się do CIL. Jeśli chcesz nowego języka (np. F #), musisz napisać dla niego tylko jeden kompilator i automatycznie uzyskać wsparcie platformy dla rzeczy obsługiwanych przez platformę .NET.

Aha, mogę pobrać bibliotekę .NET i uruchomić ją w systemie Windows lub Linux na Mono bez ponownej kompilacji (zakładając, że wszystkie moje zależności są spełnione).

Jeśli chodzi o wydajność, jest to dyskusyjne. Istnieją „prekompilatory”, które zasadniczo pobierają CIL i tworzą natywne pliki binarne. Inni twierdzą, że kompilatory just-in-time mogą dokonywać optymalizacji, których po prostu nie potrafią kompilatory statyczne. Z mojego doświadczenia wynika, że ​​wiele zależy od tego, co robi twoja aplikacja i na jakiej platformie ją uruchamiasz (głównie jak dobry jest JITer na tej platformie). Bardzo rzadko spotykam się ze scenariuszem, w którym .NET nie był wystarczająco dobry .

Telastyn
źródło
„tłumacz”? Myślałem, że zawsze stwardnienie rozsiane zapewnia tylko JITter?
Doc Brown,
1
@DocBrown - eh, tak - mylnie z mojej strony. Ustalenie.
Telastyn
+1, czy możesz dodać trochę wyjaśnienia do mojej edycji, abym mógł zaakceptować tę odpowiedź
vikkyhacks
Wysoko wydajne środowiska wykonawcze często łączą interpreter i kompilator JIT (wykonywanie w trybie mieszanym). Nie jestem pewien co do platformy .NET, ale wiele maszyn wirtualnych Java korzysta z tego podejścia.
Cyanfish,
2
@busy_wait: Wszelkiego rodzaju rzeczy. Metoda inline, propagacja kopiowania, usuwanie niepotrzebnego kodu, konwersja mnożenia / dzielenia na przesunięcia, inne operacje arytmetyczne z wykorzystaniem readonlypól. Tradycyjne kompilatory mogą wykonać niektóre z tych optymalizacji, ale tylko wtedy, gdy można je wykryć za pomocą analizy statycznej. Natomiast jitter może stwierdzić w czasie wykonywania, że ​​(na przykład) sekcja kodu nie wykonuje żadnej użytecznej pracy, ponieważ modyfikowane obiekty lub zmienne nie są nigdzie indziej wymienione. Nie jestem ekspertem od drgań, ale jest to w zasadzie kwestia siły analizy dynamicznej vs. statycznej.
Aaronaught
14

.NET ma język pośredni (CIL / MSIL) i specyficzne dla platformy implementacje niezależnego od platformy środowiska uruchomieniowego (CLR) z tego samego powodu, dla którego robi to Java. Microsoft zamierzał C # bezpośrednio konkurować z Javą, i robi to w systemach operacyjnych, na które Microsoft celuje (swoim własnym).

Korzyści, mimo że .NET jest obsługiwany tylko na platformach Windows (lub innych systemach operacyjnych, które działają podobnie do .NET, jak Mono / Linux), są podobne do Java:

  • Środowisko wykonawcze pamięci zarządzanej - w przeciwieństwie do niezarządzanego C / C ++, programiści C # / VB.NET nie muszą martwić się o ścisłą kontrolę czasu życia obiektu. Podobnie jak Java, CLR ma moduł wyrzucający elementy bezużyteczne, który automatycznie uwalnia obiekty na stercie, które opuszczają zakres. Chociaż może się to wydawać mało istotne dla kogoś przyzwyczajonego do niezarządzanych środowisk uruchomieniowych, ma on tę drugą nadzwyczajną zaletę, że zniechęca do „czarnej magii” arytmetyki wskaźników, tak powszechnej w C / C ++.
  • Niezależność od platformy - Windows Vista i Windows 7 działają inaczej niż Windows XP. Windows 8 działa nadal inaczej. Wersje Windows Mobile, w tym Windows 8 Mobile, znów działają inaczej. Inny sprzęt, inna architektura, różne możliwości. Chociaż środowisko docelowe wciąż ma znaczenie dla programisty .NET, ilość specjalistycznej wiedzy jest znacznie zmniejszona w porównaniu z tym, co trzeba wiedzieć, aby zbudować kompatybilny program C / C ++ dla wszystkich tych systemów operacyjnych. AC # dev dostaje o wiele więcej za darmo.
  • Obsługa aplikacji internetowych - jeszcze nie widziałem aplikacji internetowej skierowanej do klienta, napisanej od podstaw w C ++. W internecie serwer , na pewno, Apache, ISS, wszystkie one zwykle uruchamiane przeciwko niekontrolowana starcie z przyczyn prędkości / wydajności. Jednak C ++ nie jest językiem używanym do tworzenia aplikacji internetowych. C # to (podobnie jak Java). Został zaprojektowany od podstaw, aby wspierać następną generację paradygmatu ASP Microsoft. Jest to kod zaprojektowany do działania w piaskownicy; który piaskownica (wtyczka ASP.NET do ISS lub CLR „desktop”) jest stosunkowo nieistotna.
  • Niezależność od języka / środowiska wykonawczego - kompilator C ++ pobiera kod źródłowy C ++ i tworzy kod zestawu dla architektury jednego procesora przy użyciu jednego języka maszynowego. Aby obsługiwać inną architekturę i / lub język maszynowy, należy napisać zupełnie nowy kompilator (i skompilować całkowicie nowy zestaw bibliotek wykonawczych). Kompilator AC # pobiera kod źródłowy C # i generuje plik CIL, który specyficzny dla sprzętu JITer tłumaczy na kod maszynowy. Ten sam JITer może tłumaczyć dowolny program CIL bez względu na język źródłowy (a jest ich kilka; C #, VB.NET, F # i wiele portów języka „Iron”, takich jak IronHaskell, IronRuby, IronLisp itp.). Ten sam kompilator może przekształcić jeden język w język CIL, który może działać dowolny JITer, bez względu na sprzęt.
  • Skoncentruj się na „poprawnym” kodzie - dla programistów C ++ istnieje wiele „właściwych” sposobów na zrobienie czegoś, w zależności od tego, co najważniejsze; wydajność pamięci, wydajność procesora, niezależność sprzętowa, niezależność systemu operacyjnego itp. Kod może wyglądać drastycznie inaczej, gdy każdy z nich jest priorytetem. C # został zaprojektowany przez grupę, która wzięła sobie do serca lekcje pojęciowe Fowlera i jego współpracowników (którzy pracowali nad reformą projektowania kodu w społeczności C ++, ucząc obiektowych zasad społeczności, która w dużej mierze przeniosła się z C), ponieważ a także praktyczne lekcje wyciągnięte z języków, które pojawiły się wcześniej (w tym Java i jej niemal fanatyczne posłuszeństwo wobec wszechmogącego Obiektu, kiedy stary, dobry wskaźnik funkcji w stylu C ++ wykonałby zadanie znacznie czystiej i nie byłby mniej obiektowy zorientowany).

Ze względów antymonopolowych stwardnienie rozsiane jest ostrożne, aby nie zostać zbyt mocno zakłóconym na innych głównych platformach, takich jak Android, Mac OSX / iOS i Linux; jednak rzeczywiście istnieją zespoły rozwijające się dla wszystkich trzech platform. Istnieje opracowana przez MS wersja pakietu Office dla OSX, istnieje wiele aplikacji, w tym aplikacje Office Interop na iOS i Android, Skype (obecnie produkt Microsoft) działa na Linuksie, a Microsoft nawet widział, że przyczynia się do jądra Linuksa (głównie w sposób myślenia o wirtualizacji).

KeithS
źródło
1
„Nie widziałem jeszcze aplikacji internetowej skierowanej do klienta, napisanej od podstaw w C ++.” - gdzie umieszczasz CGI sprzed kilku lat? Moje pierwsze aplikacje internetowe (choć tak trywialne) były w 100% C. Wtedy (w połowie lat 90.) łatwiej było pisać .c i .h za wykonanie standardowej pracy w cgi (języki „skryptowe” były po prostu pojawiające się również na scenie).
hm ... CGI, CGI ... Wydaje mi się, że o tym słyszałem, ale jestem z KeithSem, jeszcze go nie widzę :)
DXM
@DXM stary model zawartości dynamicznej był dla rozwidlenia serwera WWW procesem i umieszczał rzeczy w standardowych miejscach (parametry zapytań i tym podobne były w określonych zmiennych środowiskowych) - Common Gateway Interface. Dane wyjściowe tego procesu zostały następnie odesłane jako treść. W dawnych czasach łatwiej było znaleźć programistę, który znałby C lub C ++ niż perl lub python (a sh był bardzo niezgrabny przy takiej pracy).
1
Nie lekceważ znaczenia podobieństwa z Javą. Sun właśnie pozwał MS za port JVM i wygrał pewne prawne punkty (głupio, IMHO). CIL i CLR są zainspirowane tym, a zauważysz, że J # jest tak blisko, jak to możliwe, do Java bez wywoływania dalszych działań prawnych. Ogromną różnicą jest to, że CLR jest niezależny od języka. Naprawdę możesz napisać program w kombinacji C #, F # i J #, jeśli jest to potrzebne. Po prostu spróbuj połączyć Javę z bibliotekami w innych językach i uzyskaj stabilny program.
RBerteig,
1
Ale interakcja między MSIL a kodem natywnym jest dość dobrze zdefiniowana i po prostu działa. I najwyraźniej oczekiwano, że będzie działać zgodnie z projektem i postawą społeczności użytkowników.
RBerteig
12

System operacyjny Windows jest dostępny dla różnych typów procesorów, dziś głównie x64, x86, Intel, ARM.

CIL / CLR jest niezależny od platformy sprzętowej - różnice te są „usuwane” przez środowisko wykonawcze IL. Na przykład zestaw .NET skompilowany dla „dowolnego procesora” może zwykle być wykonywany na Win64 jako proces 64-bitowy, a Win32 jako proces 32-bitowy, bez potrzeby dostarczania różnych plików wykonywalnych.

Co więcej, CIL pozwala na przechowywanie metadanych w zestawach, co nie jest łatwe w przypadku natywnych bibliotek DLL (możliwe jest oczywiście, że MS zrobił to wcześniej z komponentami COM, ale ta technologia nigdy nie była tak łatwa w obsłudze jak komponenty .NET). To sprawia, że ​​tworzenie komponentów oprogramowania jest o wiele prostsze i stanowi podstawę refleksji / introspekcji we wszystkich językach .NET.

Doktor Brown
źródło
Aby dodać do tego trochę, nie tylko pozwalają na różne typy procesorów, ale nawet różne wersje (Core i3 / i5 / i7) i dostawcy (Intel vs. AMD) w ramach tego samego typu procesora (na przykład wszystkie x64) mogą mieć różne zestawy instrukcji asemblera, które kompilator JIT mógłby wykorzystać
DXM 23.09.13
2
@DXM: i wiesz, że tak naprawdę JIT? Czy jest to bardziej hipotetyczna rzecz?
Doc Brown
Co najmniej blog MSDN twierdzi, że kompilator JIT to robi (lub zrobił to 8 lat temu).
@DocBrown: Oczywiście nie mam pod ręką żadnych materiałów referencyjnych, ale myślałem, że pamiętam coś o tym dawno temu. Dzięki delnan, za znalezienie linku. Ma to sens, ponieważ wiemy, że producenci układów lubią dodawać własne instrukcje do standardowego x86-x64, więc jeśli maszyna może skorzystać, dlaczego by tego nie zrobił?
DXM,