Przykłady kiedy użyjemy języka interpretowanego zamiast skompilowanego?

11

Rozumiem różnice między tłumaczonymi i skompilowanymi językami, ale gdyby ktoś mógł podać kilka przykładów sytuacji, w których można by używać języków interpretowanych zamiast języków skompilowanych, a także sytuacji, w których można by używać języków skompilowanych zamiast języków interpretowanych, bądź naprawdę pomocny.

KL
źródło

Odpowiedzi:

11

Według mojej wiedzy nie ma czegoś takiego jak interpretowany „język” lub skompilowany „język”.

Języki określają składnię i znaczenie słów kluczowych kodu, konstrukcji przepływu i różnych innych rzeczy, ale nie znam żadnego języka, który określa, czy należy go skompilować lub interpretować w specyfikacji języka.

Teraz, gdy masz pytanie, kiedy używasz kompilatora językowego kontra tłumacza językowego, tak naprawdę sprowadza się to do zalet / wad kompilatora vs. tłumacza i celu projektu.

Na przykład możesz użyć kompilatora JRuby dla łatwiejszej integracji z bibliotekami Java zamiast interpretera ruby ​​MRI. Prawdopodobnie istnieją również powody, aby używać interpretera ruby ​​MRI w JRuby, chociaż nie znam tego języka i nie mogę z tym rozmawiać.

Reklamowane zalety tłumaczy:

  • Brak kompilacji oznacza, że ​​czas od edycji kodu do przetestowania aplikacji może zostać skrócony
  • Nie ma potrzeby generowania plików binarnych dla wielu architektur, ponieważ interpreter będzie zarządzał abstrakcją architektury (chociaż może być konieczne martwienie się o to, że skrypty poprawnie obsługują rozmiary całkowite, a nie dystrybucję binarną)

Proponowane zalety kompilatorów:

  • Skompilowany kod natywny nie ma narzutu interpretera i dlatego zwykle jest bardziej wydajny pod względem czasu i przestrzeni
  • Interoperacyjność jest zwykle lepsza, jedynym sposobem na współpracę in-proc ze skryptami jest interpreter, a nie standardowa FFI
  • Możliwość obsługi architektur, dla których interpreter nie został skompilowany (takich jak systemy osadzone)

Założę się jednak, że w 90% przypadków będzie to wyglądać mniej więcej tak: chcę napisać to oprogramowanie w blubie, ponieważ dobrze go znam i powinno być dobre. Użyję interpretera (lub kompilatora) blub, ponieważ jest to ogólnie przyjęta kanoniczna metoda pisania oprogramowania w blubie.

Tak więc TL; DR jest po prostu, porównanie poszczególnych interpretatorów z kompilatorami dla konkretnego przypadku użycia.

Ponadto FFI: Interfejs funkcji zagranicznych, innymi słowy interfejs do współpracy z innymi językami. Więcej lektur na wikipedii

Jimmy Hoffa
źródło
2
O ile mi wiadomo, niektóre języki skryptowe dla systemu operacyjnego, takie jak ksh dla UNIX, nie mogą zostać skompilowane.
NoChance,
@ delnan, moja uwaga nie może być skompilowana za pomocą komercyjnego lub wolnego oprogramowania, które znam, nie dlatego, że nie można go skompilować z przyczyn technicznych.
NoChance,
3
@EmmadKareem Nie ma czegoś takiego jak „nie można skompilować”. Piszesz program, który czyta program w języku Li i wyprowadza równoważny program w języku La. To kompilator kompilator. Waham się przywołać argument kompletności Turinga, ponieważ w praktyce jest to czerwony śledź, ale każdy program ostatecznie zamienia się w sekwencję instrukcji kodu maszynowego. Jeśli wszystko inne zawiedzie, rozwiń pętlę interpretera (i uprość wynikowy kod, aby usunąć niepotrzebne części). Jeśli tłumacz jest napisany w języku bez tłumaczy, powtarzaj do momentu trafienia w kompilator.
1
(Zredagowałem swój komentarz, aby lepiej go sformułować, ale najwyraźniej działałem zbyt późno.) @EmmadKareem Tak, oczywiście niektóre języki nigdy nie zostały zaimplementowane za pomocą kompilatora. Ale nie rozumiem, jak to jest istotne. Jest to zawsze możliwe i wykonalne i można to zrobić w dowolnym momencie przy pewnym wysiłku. Jest to konsekwencja głównej kwestii, że język nie jest ani kompilowany, ani interpretowany z natury, i można go wdrażać na dwa sposoby. Nawiasem mówiąc, na wiele innych sposobów (no cóż, prawdopodobnie niewielkie warianty i remiksy).
2
@EmmadKareem, jeśli chcesz, możesz wziąć specyfikację języka ksh i napisać kompilator, który ją przeczyta i wygeneruje natywny plik binarny. Chodzi mi o kompilowany lub interpretowany język, który nie jest w definicji języka.
Jimmy Hoffa
8

Ważną kwestią jest to, że wiele implementacji językowych faktycznie łączy w sobie jakąś hybrydę. Wiele powszechnie używanych języków działa dzisiaj, kompilując program do formatu pośredniego, takiego jak kod bajtowy, a następnie uruchamiając go w tłumaczu. W ten sposób zazwyczaj implementowane są Java, C #, Python, Ruby i Lua. W rzeczywistości jest to zapewne sposób, w jaki większość obecnie używanych języków jest wdrażana. Faktem jest, że dzisiejszy język interpretuje i kompiluje kod. Niektóre z tych języków mają dodatkowy kompilator JIT do konwersji kodu bajtowego na kod macierzysty w celu wykonania.

Moim zdaniem powinniśmy przestać mówić o językach interpretowanych i kompilowanych, ponieważ nie są one już kategoriami użytecznymi do rozróżniania złożoności dzisiejszych implementacji językowych.

Kiedy pytasz o zalety tłumaczonych i skompilowanych języków, prawdopodobnie masz na myśli coś innego. Być może pytasz o zalety pisania statycznego / dynamicznego, zalety dystrybucji natywnych plików wykonywalnych, względne zalety kompilacji JIT i AOT. Są to wszystkie problemy, które łączą się z interpretacją / kompilacją, ale są różnymi zagadnieniami.

Winston Ewert
źródło
2

Przede wszystkim język programowania można interpretować i kompilować. Interpretacja i kompilacja to tylko metody generowania kodu wykonywalnego z kodu źródłowego. W przypadku interpretera kod źródłowy jest odczytywany i interpretowany przez interpretera, który następnie wykonuje kod podczas jego interpretacji. Z drugiej strony kompilator odczytuje kod źródłowy i generuje wykonywalny plik binarny z kodu źródłowego - dzięki czemu program może być uruchamiany jako osobny proces niezależnie.

Teraz, zanim ktokolwiek się zastanowi ... Tak, C / C ++ / C # / Java można interpretować i tak, można skompilować skrypty JavaScript i Bash. To, czy istnieją działający tłumacze ustni lub kompilatory dla tych języków, to kolejne pytanie.

Teraz, aby odpowiedzieć na pytanie, kiedy użyjemy „języka interpretowanego” zamiast „języka skompilowanego”. Samo pytanie jest nieco mylące, ale zakładam, że oznacza to, kiedy wolę interpretację niż kompilację. Jedną z wad kompilacji jest to, że generuje pewne obciążenie z powodu procesu kompilacji - kod źródłowy musi zostać skompilowany do wykonywalnego kodu maszynowego, więc nie nadaje się do zadań wymagających minimalnego opóźnienia podczas wywoływania kodu źródłowego w celu wykonania programu. Z drugiej strony skompilowany kod źródłowy jest prawie zawsze szybszy niż równoważny zinterpretowany kod źródłowy z powodu narzutu spowodowanego interpretacją kodu. Z drugiej strony tłumacze mogą wywoływać i uruchamiać kod źródłowy z bardzo małym narzutem wywołania, ale kosztem wydajności w czasie wykonywania.

W końcu prawie niemożliwe jest podanie jakichkolwiek konkretnych przypadków użycia, kiedy wolą jeden po drugim, ale na przykład jeden (do mojego podkreślającego, bardzo nierealistycznego) przypadek byłby, gdy kod źródłowy programu zmienia się dynamicznie między wywołaniami programu, a narzut kompilacji jest zbyt duży wysoki, aby był to realny wybór. W takim przypadku prawdopodobnie pożądana byłaby interpretacja kodu źródłowego zamiast kompilacji.

Istnieje jednak coś, co można uznać za przykład z prawdziwego świata: ukrywanie kodu źródłowego po wdrożeniu. Z natywnieskompilowany kod programista wdraża wykonywalny kod macine programu i danych. W przypadku interpretowanego kodu należy wdrożyć sam kod źródłowy, który można następnie sprawdzić i poddać inżynierii wstecznej przy znacznie mniejszym nakładzie pracy niż w przypadku natywnego kodu maszynowego. Jedynym wyjątkiem są języki takie jak C # i Java, które kompilują się do bezpośredniego języka / kodu bajtowego (MSIL dla C # i kodu bajtowego Java dla Java), które następnie są wdrażane i kompilowane „na czas” w czasie wykonywania, podobnie jak robi to interpreter. Istnieją jednak tak zwane dekompilatory dla MSIL i Java Bytecode, które mogą rekonstruować oryginalny kod źródłowy ze względnie dobrą dokładnością i jako takie, inżynieria wsteczna takich produktów jest znacznie bardziej trywialna niż produkty inżynierii wstecznej, które są wdrażane w natywnym kodzie maszynowym.

zxcdw
źródło
1
Robisz dobre punkty, ale będąc pedantem, mam problem z niektórymi frazesami (oba odnoszą się do trzeciego akapitu): 1. Tłumacz nie kompiluje. 2. Jest zrozumiałe (choć te warunki są rzadkie), że zły, nieoptymalizujący kompilator jest pokonany przez wysoce zoptymalizowany (szczególnie oparty na kodzie bajtowym) interpreter. Dzieje się to podwójnie, jeśli policzysz kompilatory JIT pod tłumaczami (czego wolę nie robić, ale niektórzy to robią).
@delnan Być może jest źle sformułowany, nie jestem rodzimym językiem angielskim. Jednak, o ile mogę powiedzieć, akapit trzeci nie oznacza, że ​​interpreter dokonałby kompilacji. Po drugie, podkreśliłem słowo równoważne podkreśleniu podobieństwa skompilowanego i zinterpretowanego kodu, aby wykluczyć przypadki słabego kompilatora w porównaniu z wysokowydajnym interpreterem, być może nie byłem tego jasny, ale nie widzę tego rozsądne jest skupienie się na wyjaśnieniu takich ekstremalnych przypadków, ponieważ nie ma to żadnego wpływu na różnice między wykonywaniem kodu źródłowego przez kompilowanie lub iterpretowanie
zxcdw
Przepraszam, bez względu na pierwszy punkt, coś źle odczytałem. Mea culpa. Co do drugiego punktu: wziąłem „równoważny” w odniesieniu do kodu, który jest interpretowany lub kompilowany (a porównywanie kompilatora i interpretera nie ma większego sensu, ponieważ robią one zasadniczo różne rzeczy). Nie sądzę, że trzeba tracić czasu wyszczególnieniem dziwaczne przypadki jak mój przykład, ale wolałbym upuszczenie „zawsze” na rzecz frazowania, który wyjaśnia , dlaczego to może być szybszy w pierwszej kolejności: Nie interpreter napowietrznych [które powinny być zdefiniowane IMHO] oraz możliwość przeprowadzenia optymalizacji przed uruchomieniem.
1

Mogę wymyślić następujące scenariusze, gdy używasz tłumaczonego języka:

  • Tam, gdzie nie ma kompilatora, na przykład skrypty powłoki Linux / Unix .
  • Szybkie i brudne skrypty, które rozwiązują mały problem
  • Języki, które ułatwiają pisanie dynamicznych stron HTML i są ogólnie interpretowane jak JSP (Tomcat kompiluje to w previos do uruchomienia), PHP, ASP itp.

Mogę wymyślić następujące scenariusze, gdy chcesz skompilować kod:

  • Musisz rozpowszechniać pliki binarne, ponieważ Twoja aplikacja jest zamkniętym źródłem i nie chcesz rozdawać kodu źródłowego.
  • Szybkość, podobnie jak systemy wbudowane i tym podobne.
  • Potrzebujesz poziomu bezpieczeństwa typu kodu, który może zapewnić tylko kompilator ze ściśle wpisanym językiem. Kompilatory ujawniają literówki w każdym zakątku kodu źródłowego, podczas gdy w interpretowanych programach literówki mogą zostać nieodkryte w kodzie produkcyjnym.
  • Duże , złożone systemy: nie wyobrażam sobie systemu operacyjnego ani pakietu biurowego jako niczego innego niż skompilowane pliki binarne.
  • Chcesz usunąć każdy drobny narzut z drogi i potrzebujesz dobrej komunikacji z fragmentami asemblera (trudne z każdym rodzajem środowiska uruchomieniowego, szczególnie z tłumaczem) (ten punkt spowodowany komentarzem @delnam)
Tulains Córdova
źródło
3
Tłumacz języka sprawia, że ​​język jest nie mniej mocno pisany. Haskell jest wyjątkowo silnie napisany i możesz używać GHCI, aby skutecznie go interpretować. Silne / słabe pisanie to aspekty języka, a nie aspekty kompilatora lub tłumacza.
Jimmy Hoffa
1
-1 Na ​​temat kompilacji profesjonalistów: (1) Kompilowanie kodu nie chroni przed inżynierią wsteczną, po prostu czyni go nieco trudniejszym. (2) Kompilacja (usunięcie narzutu interpretera, zautomatyzowana optymalizacja kodu aplikacji) jest tylko jednym źródłem wydajności i jest przewyższona ręcznie wykonanymi wielkoskalowymi optymalizacjami przez ludzkiego eksperta. (3) Sprawdzanie typu, choć zwykle połączone z kompilacją, jest od niego niezależne. Sprawdzanie typu to przepustka do analizy statycznej; może się to zdarzyć bez emisji kodu i przed interpretacją kodu. (4) Wydaje się dość fałszywy. „Nie możesz sobie tego wyobrazić”? Czemu? Jak to jest wymagane?
1
Inne tłumaczone języki istnieją, ilekroć w innym programie jest tłumacz. Ilekroć używa się wzorca interpretera , istnieje zinterpretowany język o pewnej złożoności.
3
„skrypty” niekoniecznie są interpretowane. Wiele języków „skryptowych” jest kompilowanych do kodu bajtowego dla maszyny wirtualnej, która jest następnie wykonywana (patrz lua, perl, python, ruby). Nie ma prawdziwej różnicy między tym a java poza tym, kiedy ma miejsce kompilacja.
3
+1, myślę, że jest to odpowiedź, jakiej naprawdę szukał PO, i chociaż punkty mogą nie być w 100% prawdziwe, jak wskazano, istnieje co najmniej 95% prawdy ze względów praktycznych.
Doc Brown,
1

Ostatecznie duży kompromis polega na produktywności (ile linii kodu musisz napisać) i wydajności (jak szybko twój program wykona).

Ponieważ języki interpretowane po przekształceniu w informacje o procesorze zawierają więcej informacji, mogą polegać na refleksji i dynamicznym pisaniu, co znacznie zwiększa wydajność . Kolejną zaletą języków interpretowanych jest to, że są one niezależne od platformy, o ile istnieje platforma dla tłumacza.

Ponieważ procesor nie może przekształcać kodu języka w kod maszynowy i uruchamiać go w tym samym czasie, jak w interpretowanym przypadku, języki kompilowane dają szybsze programy. Ponadto system wbudowany w język kompilowany jest bezpieczniejszy, ponieważ może wykrywać problemy w czasie kompilacji, co w zasadzie oznacza, że widzisz błąd podczas pisania (z nowoczesnymi IDE) zamiast go widzieć tylko wtedy, gdy faktycznie uruchomisz program (oczywiście , to nie naprawia błędów logicznych).

Znając to, tłumaczone języki są odpowiednie dla:

  1. Produktywny rozwój: szybkie tworzenie stron internetowych (PHP, Javascript) lub do prototypowania.
  2. Wieloplatformowy; na przykład JavaScript jest obsługiwany w każdej przeglądarce (włączając przeglądarki mobilne).

Języki skompilowane są odpowiednie, gdy:

  1. Wydajność ma kluczowe znaczenie (systemy operacyjne) lub zasoby są ograniczone (mikrokontrolery).
  2. Systemy do zbudowania są złożone; przy budowaniu dużych systemów (systemów korporacyjnych) języki skompilowane są niezbędne do obsługi wielu możliwych błędów, które mogą pojawić się w językach interpretowanych; również złożone programy wymagają wielu zasobów, a równowaga ma tendencję do kompilowania języków.
m3th0dman
źródło
-1, ponieważ sugerujesz, że wszystkie interpretowane języki są wpisywane dynamicznie, a wszystkie języki kompilowane są wpisywane statycznie, co jest całkowicie nieprawdziwe.
Daniel Pryden
@DanielPryden To musi być czysty zbieg okoliczności, fakt, że prawie wszystkie interpretowane języki są pisane dynamicznie, a skompilowane są pisane statycznie? Czy to przypadek, że model typu dynamicznego jest odpowiedni dla języków interpretowanych?
m3th0dman
Z różnych powodów istnieje korelacja, ale nie jest to wymóg. To pytanie zostało faktycznie zadane na StackOverflow: Dlaczego interpretowane języki są najczęściej uchylone, podczas gdy kompilacja ma silne pisanie?
Daniel Pryden,
1
Erlang jest kompilowany i dynamicznie wpisywany. Haskell jest wpisany statycznie i można go skompilować lub zinterpretować
Zachary K
1
@ZacharyK Erlang ma system czasu wykonywania; Haskell jest kompilowany w większości przypadków (napisane programy).
m3th0dman
1

Oprócz powodów, o których wspominali inni, istnieje jeden szczególnie ważny przypadek użycia przy wyborze interpretacji ad hoc zamiast dowolnej formy kompilacji lub dowolnego podejścia hybrydowego.

W przypadku, gdy język programowania jest używany jako protokół komunikacyjny i gdy ważne jest opóźnienie odpowiedzi, bardziej sensowne jest unikanie marnowania czasu na kompilację i ewentualne przetwarzanie wstępne.

Dotyczy to na przykład języków agentów lub sposobu, w jaki, powiedzmy, Tcl / Tk jest zwykle używany.

Innym możliwym powodem trzymania się interpretacji jest użycie interpretera języka do samego ładowania lub bardziej rozbudowanego języka wyższego poziomu, a jego prostota jest ważniejsza niż wydajność procesu ładowania.

Dla prawie każdego innego możliwego przypadku użycia kompilacja (lub podejście hybrydowe) jest lepszym rozwiązaniem.

Logika SK
źródło