Jak zaimplementowane są wyjątki pod maską?

Prawie każdy z nich korzysta, ale wielu, w tym ja, bierze to za pewnik, że po prostu działają.

Szukam wysokiej jakości materiału. Języki, których używam to: Java, C, C#, Python, C++, więc są one dla mnie najbardziej interesujące.

Teraz, C++ jest prawdopodobnie dobrym miejscem do rozpoczęcia, ponieważ można rzucić wszystko w tym języku.

Również C jest blisko montażu. Jak można emulować wyjątki używając czystych konstrukcji C i bez montażu?

W końcu usłyszałem plotkę że pracownicy Google nie stosują wyjątków dla niektórych projektów ze względu na szybkość. Czy to tylko plotka? Jak bez nich można osiągnąć coś istotnego?

Dziękuję.

Author: Billy ONeal, 2010-01-03

10 answers

Wyjątki są tylko konkretnym przykładem bardziej ogólnego przypadku zaawansowanych nielokalnych konstrukcji sterowania przepływem. Inne przykłady to:

  • notifications (uogólnienie WYJĄTKÓW, pierwotnie z jakiegoś starego systemu Obiektowego Lispu, obecnie zaimplementowanego np. w CommonLisp i Ioke),
  • kontynuacje (bardziej ustrukturyzowana forma GOTO, popularna w językach wyższego rzędu),
  • coroutines (uogólnienie podprogramów, popularne zwłaszcza w Lua),
  • Generatory ]}
  • włókna (kooperacyjne lekkie nici) i oczywiście wspomniane już
  • GOTO.

(jestem pewien, że jest wiele innych, za którymi tęskniłem.)

Ciekawą właściwością tych konstrukcji jest to, że wszystkie są mniej więcej równoważne w sile ekspresyjnej: jeśli masz Jeden , możesz dość łatwo zbudować wszystkie i inni

Tak więc, jak najlepiej zaimplementujesz wyjątki, zależy od tego, jakie inne konstrukcje masz dostępne:

  • każdy procesor mA GOTO, dlatego zawsze możesz do tego wrócić, jeśli musisz.
  • C ma setjmp/longjmp które są w zasadzie kontynuacjami MacGyvera (zbudowane z taśmy klejącej i wykałaczek, nie do końca prawdziwe, ale przynajmniej wyciągnie cię z natychmiastowych kłopotów, jeśli nie masz czegoś lepszego dostępnego).
  • JVM i CLI mają wyjątki od ich własnych, co oznacza, że jeśli semantyka WYJĄTKÓW Twojego języka pasuje do/C#Javy, jesteś wolny (ale jeśli nie, to masz przerąbane).
  • Parrot VM jako wyjątki i kontynuacje.
  • Windows posiada własny framework do obsługi wyjątków, którego implementatorzy języka mogą używać do budowania własnych WYJĄTKÓW na wierzchu.

Bardzo ciekawy przypadek użycia, zarówno użycie WYJĄTKÓW jak i implementacja wyjątek stanowi projekt Volta Microsoft Live Lab. (Obecnie nieistniejące.) Celem Volta było zapewnienie architektonicznego refaktoringu dla aplikacji internetowych za naciśnięciem jednego przycisku. Możesz więc zmienić jednowarstwową aplikację webową w dwu-lub trzywarstwową, po prostu umieszczając atrybuty [Browser] lub [DB] na kodzie. NET, A kod będzie automatycznie uruchamiany na kliencie lub w DB. Aby to zrobić, kod. NET musiał zostać przetłumaczony na kod źródłowy JavaScript, oczywiście.

Teraz możesz po prostu napisać całą maszynę wirtualną w JavaScript i uruchomić kod bajtowy niezmodyfikowany. (Zasadniczo, port CLR z C++ do JavaScript.) Istnieją rzeczywiście projekty, które to robią (np. HotRuby VM), ale jest to zarówno nieefektywne, jak i mało interoperacyjne z innym kodem JavaScript.

Zamiast tego napisali kompilator, który kompiluje bajt CIL do kodu źródłowego JavaScript. Jednak JavaScript brakuje pewnych funkcji, które ma. NET (Generatory, wątki, również dwa modele WYJĄTKÓW nie są w 100% kompatybilne), a co ważniejsze, brakuje pewnych funkcji, które twórcy kompilatora kochają (albo GOTO lub kontynuacje) i które mogłyby zostać użyte do implementacji wyżej wymienionych brakujących funkcji.

Jednak JavaScript ma wyjątki. Tak więc, użyli WYJĄTKÓW JavaScript do zaimplementowania ciągów Volta, a następnie użyli ciągów Volta do zaimplementowania WYJĄTKÓW. NET , . Net Generatory a nawet . Net zarządzane wątki (!!!)

Więc, aby odpowiedzieć na twoje pierwotne pytanie:

Jak zaimplementowane są wyjątki pod maską?

Z wyjątkami, jak na ironię! Przynajmniej w tym konkretnym przypadku.

Innym świetnym przykładem są niektóre propozycje WYJĄTKÓW na liście dyskusyjnej Go, które implementują wyjątki za pomocą Goroutines (coś w rodzaju mieszaniny współbieżnych coroutines i procesów CSP). Jeszcze innym przykładem jest Haskell, który używa Monad, leniwej oceny, optymalizacji wywołań ogonowych i funkcji wyższego rzędu do implementacji WYJĄTKÓW. Niektóre nowoczesne procesory obsługują również podstawowe bloki konstrukcyjne dla WYJĄTKÓW (na przykład Procesory Vega-3, które zostały zaprojektowane specjalnie dla akceleratorów obliczeniowych Java Azul Systems).

 39
Author: Jörg W Mittag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-03 19:24:44

Oto wspólny sposób implementacji WYJĄTKÓW w C++ :
http://www.codesourcery.com/public/cxx-abi/abi-eh.html

Jest przeznaczony dla architektury Itanium, ale opisywana tutaj implementacja jest używana również w innych architekturach. Zauważ, że jest to długi dokument, ponieważ wyjątki w C++ są skomplikowane.

Oto dobry opis jak LLVM implementuje wyjątki:
http://llvm.org/docs/ExceptionHandling.html

Ponieważ LLVM ma być wspólna reprezentacja pośrednia dla wielu uruchomień, opisane mechanizmy mogą być stosowane w wielu językach.

 22
Author: Adam Goode,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-03 18:18:44

W swojej książce C Interfaces and Implementations: Techniques for Creating Reusable Software, D. R. Hanson dostarcza miłą implementację WYJĄTKÓW w czystym C przy użyciu zestawu makr i setjmp/longjmp. Dostarcza makra TRY/RAISE/EXCEPT/FINALLY, które mogą emulować prawie wszystko, co robią wyjątki C++ i nie tylko.

Kod można przejrzeć tutaj (spójrz na except.H / z wyjątkiem.c).

P. S. pytanie o Google. Ich pracownicy mają prawo do korzystania z wyjątki w nowym kodzie, a oficjalnym powodem bana w starym kodzie jest to, że był już napisany w ten sposób i nie ma sensu mieszać stylów. Osobiście uważam też, że C++ bez wyjątków nie jest najlepszym pomysłem.
 17
Author: Eli Bendersky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-03 18:11:41

Kompilatory C/C++ wykorzystują podstawowe funkcje systemu operacyjnego do obsługi wyjątków. Frameworki takie jak. Net czy Java również polegają, w maszynie wirtualnej, na obiektach systemu operacyjnego. Na przykład w systemie Windows prawdziwe podnoszenie ciężarów odbywa się przez Seh, strukturyzowaną infrastrukturę obsługi wyjątków. Powinieneś koniecznie przeczytać stary artykuł referencyjny: A Crash Course on the Depths of Win32™ Structured Exception Handling .

Co do kosztów nieużywania WYJĄTKÓW, to są drogie, ale w porównaniu z czym? W porównaniu do kodów błędów zwrotnych? Po uwzględnieniu kosztów poprawności i jakości kodu wyjątki zawsze wygrywają w przypadku aplikacji komercyjnych. Poza kilkoma bardzo krytycznymi funkcjami na poziomie systemu operacyjnego, wyjątki są zawsze lepsze.

Ostatni, ale nie mniej ważny, jest anty-wzorzec używania WYJĄTKÓW do kontroli przepływu. Wyjątki powinny być wyjątkowe, a kod, który nadużywa wyjątków od kontroli przepływu, zapłaci cenę w wydajności.

 7
Author: Remus Rusanu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-03 18:14:19

Najlepszą pracą napisaną na temat implementacji WYJĄTKÓW (pod maską) jest Obsługa wyjątków w CLU autorstwa Barbary Liskow i Alana Snydera. Odnosiłem się do niego za każdym razem, gdy uruchamiałem nowy kompilator.

Dla nieco wyższego poziomu widoku implementacji w C przy użyciu setjmp i longjmp, polecam Interfejsy i implementacje Dave ' a Hansona C (jak Eli Bendersky).

 6
Author: Norman Ramsey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-04 01:58:16

Kluczową rzeczą, którą implementacja WYJĄTKÓW musi obsłużyć, jest sposób powrotu do obsługi wyjątków po wyrzuceniu wyjątku. Ponieważ możesz wykonać dowolną liczbę zagnieżdżonych wywołań funkcji od instrukcji try w C++, musi rozwinąć stos wywołań szukając obsługi. Jednak zaimplementowane, musi to pociągnąć za sobą koszt rozmiaru kodu utrzymania wystarczającej ilości informacji w celu wykonania tej operacji (i ogólnie oznacza tabelę danych dla wywołań które mogą przyjmować wyjątki). Oznacza to również, że ścieżka wykonania kodu dynamicznego będzie dłuższa niż po prostu powrót z wywołań funkcji(co jest dość niedrogą operacją na większości platform). W zależności od wdrożenia mogą wystąpić również inne koszty.

Koszt względny będzie się różnić w zależności od używanego języka. Im wyższy poziom języka, tym mniej prawdopodobne, że koszt rozmiaru kodu będzie miał znaczenie, a Informacje mogą być przechowywane niezależnie od tego, czy wyjątki są używany.

Aplikacja, w której Korzystanie z wyjątków (i C++ w ogóle) jest często unikane z dobrych powodów jest wbudowany firmware. W typowych małych platformach typu bare metal lub RTOS możesz mieć 1MB miejsca na kod lub 64K, a nawet mniej. Niektóre platformy są tak małe, że nawet C nie jest praktyczne w użyciu. W tego rodzaju środowisku wpływ wielkości jest istotny ze względu na koszty wymienione powyżej. Ma również wpływ na samą bibliotekę standardową. Dostawcy wbudowanych łańcuchów narzędzi często wytwarzają bibliotekę bez wyjątku, co ma ogromny wpływ na rozmiar kodu. Wysoce optymalizujące Kompilatory mogą również analizować callgraph i optymalizować potrzebne informacje o ramce wywołania dla operacji unwind w celu znacznej redukcji miejsca. Wyjątki utrudniają również analizę trudnych wymagań w czasie rzeczywistym.

W bardziej typowych środowiskach koszt rozmiaru kodu jest prawie na pewno nieistotny, a współczynnik wydajności jest prawdopodobnie kluczowy. To, czy ich użyjesz, zależy od twojej wydajności wymagania i sposób ich wykorzystania. Korzystanie z wyjątków w wyjątkowych przypadkach może stworzyć elegancki projekt, ale przy kosztach wydajności, które mogą być nie do przyjęcia dla Systemów o wysokiej wydajności. Implementacje i koszt względny będą się różnić w zależności od platformy i kompilatora, więc najlepszym sposobem, aby naprawdę zrozumieć, czy wyjątki są problemem, jest analiza wydajności własnego kodu.

 4
Author: djs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-03 19:33:11

setjmp() i longjmp() zazwyczaj.

Wyłapywanie WYJĄTKÓW ma niebanalny koszt, ale dla większości celów nie jest to wielka sprawa.

 4
Author: Ignacio Vazquez-Abrams,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-07 19:36:40

Kod C++ w Google (z wyjątkiem niektórych przypadków specyficznych dla Windows) nie używa WYJĄTKÓW: cfr the guidelines , krótka forma: "We do not use C++ exceptions". Cytowanie z dyskusji (naciśnij strzałkę, aby rozwinąć adres URL):

Nasza rada przed używaniem wyjątków jest nie opiera się na filozoficznych lub podstawy moralne, ale praktyczne. Ponieważ chcielibyśmy skorzystać z naszego projekty open-source w Google i trudno to zrobić, jeśli te projekty wykorzystują wyjątki, potrzebujemy na odradzam wyjątki w Google również projekty open-source. Rzeczy pewnie byłoby inaczej, gdybyśmy mieli żeby zrobić to od nowa.

Zasada ta nie ma zastosowania do kodu Google w innych językach, takich jak Java i Python.

 3
Author: Alex Martelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-03 18:49:51

Jeśli chodzi o wydajność-rzadkie stosowanie wyjątków prawdopodobnie będzie miało znikome skutki, ale nie nadużywaj ich.

Osobiście widziałem Kod Javy, który wykonywał dwa rzędy wielkości gorzej niż mógł (zajął około x100 czasu), ponieważ wyjątki były używane w ważnej pętli zamiast bardziej standardowych if/returns.

 1
Author: Oak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-03 18:16:05

Niektóre środowiska uruchomieniowe, takie jak Objective-C runtime mają zerowe 64-bitowe wyjątki. Oznacza to, że wejście do bloku prób nic nie kosztuje. Jest to jednak dość kosztowne, gdy wyjątek jest wyrzucany. Wynika to z paradygmatu "optymalizacji dla przeciętnego przypadku" - wyjątki mają być wyjątkowe, więc lepiej jest zrobić przypadek, gdy wyjątki nie istnieją naprawdę szybko, nawet jeśli odbywa się to kosztem znacznie wolniejszych WYJĄTKÓW.

 1
Author: Mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-03 18:59:46