Jeśli dobrze pamiętam kurs mojego kompilatora, typowy kompilator ma następujący uproszczony zarys:
- Analizator leksykalny skanuje (lub wywołuje funkcję skanowania) kod źródłowy znak po znaku
- Ciąg znaków wejściowych jest sprawdzany pod kątem poprawności ze słownikiem leksemów
- Jeśli leksem jest ważny, jest on następnie klasyfikowany jako token, któremu odpowiada
- Analizator składni sprawdza składnię kombinacji tokenów; token po tokenie .
Czy teoretycznie wykonalne jest podzielenie kodu źródłowego na ćwiartki (lub jakikolwiek inny mianownik) i wielowątkowość procesu skanowania i analizy? Czy istnieją kompilatory wykorzystujące wielowątkowość?
multithreading
compiler
parsing
8 protonów
źródło
źródło
Odpowiedzi:
Duże projekty oprogramowania zwykle składają się z wielu jednostek kompilacji, które można kompilować stosunkowo niezależnie, dlatego kompilacja jest często równoległa z bardzo zgrubną szczegółowością poprzez kilkakrotne wywoływanie kompilatora. Dzieje się tak na poziomie procesów systemu operacyjnego i jest koordynowane przez system kompilacji, a nie przez kompilator. Zdaję sobie sprawę, że nie o to pytałeś, ale jest to najbardziej zbliżona do równoległości w większości kompilatorów.
Dlaczego? Cóż, większość pracy wykonywanej przez kompilatory nie daje się łatwo zrównoleglać:
Po tym jest nieco łatwiej. Sprawdzanie i optymalizacja typów oraz generowanie kodu mogą być w zasadzie zrównoleglone przy ziarnistości funkcji. Wciąż wiem o kilku, jeśli w ogóle to robią kompilatory, być może dlatego, że wykonywanie tak dużych zadań jednocześnie jest dość trudne. Trzeba także wziąć pod uwagę, że większość dużych projektów oprogramowania zawiera tak wiele jednostek kompilacyjnych, że podejście „uruchom kilka kompilatorów równolegle” jest całkowicie wystarczające, aby utrzymać wszystkie rdzenie (a w niektórych przypadkach nawet całą farmę serwerów). Ponadto w przypadku dużych zadań kompilacji dyskowe operacje we / wy mogą stanowić tak samo wąskie gardło, jak faktyczna praca kompilacji.
To powiedziawszy, znam kompilator, który równolegle pracuje nad generowaniem i optymalizacją kodu. Kompilator Rust może dzielić pracę zaplecza (LLVM, która faktycznie obejmuje optymalizacje kodu, które tradycyjnie uważa się za „środkowy koniec”) na kilka wątków. Nazywa się to „jednostkami genów kodu”. W przeciwieństwie do innych możliwości równoległości omówionych powyżej, jest to ekonomiczne, ponieważ:
źródło
Kompilacja to problem „żenująco równoległy”.
Nikt nie dba o czas na skompilowanie jednego pliku. Ludziom zależy na czasie kompilacji 1000 plików. A dla 1000 plików każdy rdzeń procesora może z przyjemnością skompilować jeden plik na raz, utrzymując wszystkie rdzenie całkowicie zajęte.
Wskazówka: „make” używa wielu rdzeni, jeśli dasz mu właściwą opcję wiersza poleceń. Bez tego kompiluje jeden plik po drugim w systemie 16-rdzeniowym. Co oznacza, że możesz go skompilować 16 razy szybciej, zmieniając opcje wiersza o jedną linię.
źródło