Dlaczego Python został napisany za pomocą GIL?


112

Globalna blokada interpretera (GIL) wydaje się często cytowana jako główny powód, dla którego wątki i tym podobne są trudne w Pythonie - co rodzi pytanie „Dlaczego tak się stało?”

Nie będąc programistą, nie mam pojęcia, dlaczego tak się dzieje - jaka była logika wprowadzenia GIL?


10
Artykuł w Wikipedii stwierdza, że „GIL może być znaczącą barierą dla paralelizmu - ceną płaconą za dynamikę języka” , i dodaje, że „Powody stosowania takiej blokady obejmują: zwiększenie szybkości programów jednowątkowych (brak konieczności uzyskiwania lub zwalniania blokad wszystkich struktur danych osobno) oraz łatwa integracja bibliotek C, które zwykle nie są bezpieczne dla wątków. ”
Robert Harvey

3
@RobertHarvey, Dynamism nie ma z tym nic wspólnego. Problemem jest mutacja.
dan_waterworth


1
Nic nie może poradzić na to, że podobnie jak brak niepodpisanych cyfr w Javie, miał on na celu zapobieżenie, by ludzie, którzy nie wiedzą, co robią, strzelali sobie w stopy. Niestety, ktoś, kto nie wie, co robią dostaje język niedoborem, który jest prawdziwy wstyd, ponieważ Python skał w wielu innych sposobów
Podstawowe

1
@Basic musi istnieć jakiś standardowy sposób radzenia sobie z tablicami bajtów w Javie (nie używałem go od dawna), aby wykonać matematykę kryptograficzną. Python (na przykład) nie ma podpisanych liczb, ale nie próbowałbym nawet robić z nim operacji bitowych, ponieważ istnieją lepsze sposoby.
Nick T

Odpowiedzi:


105

Istnieje kilka implementacji języka Python, na przykład CPython, IronPython, RPython itp.

Niektóre z nich mają GIL, inne nie. Na przykład CPython ma GIL:

From http://en.wikipedia.org/wiki/Global_Interpreter_Lock

Aplikacje napisane w językach programowania z GIL można zaprojektować tak, aby korzystały z oddzielnych procesów w celu osiągnięcia pełnej równoległości, ponieważ każdy proces ma własnego interpretera, a z kolei własny GIL.

Korzyści z GIL

  • Zwiększona prędkość programów jednowątkowych.
  • Łatwa integracja bibliotek C, które zwykle nie są bezpieczne dla wątków.

Dlaczego Python (CPython i inni) korzysta z GIL

W CPython globalna blokada interpretera (GIL) to muteks, który uniemożliwia wielu wątkom natywnym wykonywanie bajtów kodu Pythona jednocześnie. Ta blokada jest konieczna głównie dlatego, że zarządzanie pamięcią CPython nie jest bezpieczne dla wątków.

GIL jest kontrowersyjny, ponieważ uniemożliwia wielowątkowym programom CPython pełne wykorzystanie systemów wieloprocesorowych w określonych sytuacjach. Należy pamiętać, że potencjalnie blokujące lub długotrwałe operacje, takie jak operacje we / wy, przetwarzanie obrazu i niszczenie liczb NumPy, mają miejsce poza GIL. Dlatego tylko w programach wielowątkowych, które spędzają dużo czasu w GIL, interpretując kod bajtowy CPython, GIL staje się wąskim gardłem.

Python ma GIL w przeciwieństwie do drobnoziarnistego blokowania z kilku powodów:

  • Jest szybszy w przypadku jednowątkowym.

  • Jest szybszy w przypadku wielowątkowych programów związanych z operacjami we / wy.

  • Jest to szybsze w wielowątkowym przypadku programów związanych z procesorem, które wykonują intensywną pracę obliczeniową w bibliotekach C.

  • Ułatwia to pisanie rozszerzeń C: nie będzie przełączania wątków Pythona, chyba że pozwalasz na to (np. Między makrami Py_BEGIN_ALLOW_THREADS i Py_END_ALLOW_THREADS).

  • Ułatwia to pakowanie bibliotek C. Nie musisz się martwić o bezpieczeństwo wątków. Jeśli biblioteka nie jest bezpieczna dla wątków, po prostu trzymaj GIL zablokowany podczas jego wywoływania.

GIL można wydać za pomocą rozszerzeń C. Standardowa biblioteka Pythona uwalnia GIL wokół każdego blokującego wywołania we / wy. Zatem GIL nie ma wpływu na wydajność serwerów powiązanych z operacjami we / wy. Możesz zatem tworzyć serwery sieciowe w Pythonie, używając procesów (rozwidlenia), wątków lub asynchronicznych operacji we / wy, a GIL nie będzie przeszkadzał.

Biblioteki numeryczne w C lub Fortran można podobnie wywoływać po wydaniu GIL. Podczas gdy twoje rozszerzenie C czeka na zakończenie FFT, interpreter będzie wykonywał inne wątki Pythona. W tym przypadku GIL jest więc łatwiejszy i szybszy niż drobnoziarniste ryglowanie. Stanowi to większość pracy numerycznej. Rozszerzenie NumPy uwalnia GIL, gdy tylko jest to możliwe.

Wątki są zwykle złym sposobem na pisanie większości programów serwerowych. Jeśli obciążenie jest niskie, rozwidlenie jest łatwiejsze. Jeśli obciążenie jest wysokie, lepsze jest asynchroniczne we / wy i programowanie sterowane zdarzeniami (np. Przy użyciu Twisted Framework Pythona). Jedyną wymówką do używania wątków jest brak os.fork w systemie Windows.

GIL stanowi problem tylko wtedy, gdy wykonujesz intensywną pracę procesora w czystym języku Python. Tutaj możesz uzyskać bardziej przejrzysty projekt za pomocą procesów i przekazywania wiadomości (np. Mpi4py). W sklepie z serami Python znajduje się również moduł „przetwarzania”, który zapewnia procesom taki sam interfejs jak wątki (tj. Zamienia wątki. Wątek na przetwarzanie.Proces).

Wątki mogą być używane do utrzymania responsywności GUI niezależnie od GIL. Jeśli GIL pogarsza twoją wydajność (por. Powyższa dyskusja), możesz pozwolić, aby Twój wątek odrodził się proces i czekał na jego zakończenie.


52
Brzmi dla mnie jak kwaśne winogrona. Python nie może poprawnie wykonywać wątków, więc wymyślasz powody, dla których wątki są niepotrzebne lub nawet złe. „Jeśli obciążenie jest niskie, rozwidlenie jest łatwiejsze”, poważnie? A GIL jest „szybszy” we wszystkich tych przypadkach tylko wtedy, gdy nalegasz na użycie GC z liczeniem referencji.
Michael Borgwardt

9
s/RPython/PyPy/g. @MichaelBorgwardt Podawanie powodów dla pro GIL jest w pewnym sensie pytaniem, prawda? Chociaż zgodziłbym się, że część treści tej odpowiedzi (a mianowicie omówienie alternatyw) jest nie na temat. A dla lepszego lub gorszego, ponowne liczenie jest teraz prawie niemożliwe do pozbycia się - jest głęboko zakorzenione w całym API i bazie kodu; prawie niemożliwe jest pozbycie się go bez przepisania połowy kodu i złamania całego kodu zewnętrznego.

10
Nie zapomnij o multiprocessingbibliotece - standard od wersji 2.6. Jego pule robocze są superszybką abstrakcją dla niektórych prostych rodzajów równoległości.
Sean McSomething

8
@alcalde Tylko jeśli nie wiesz, co robisz i / lub nie chcesz, aby twoje wątki mogły współpracować / komunikować się. W przeciwnym razie jest to królewski ból z tyłu, szczególnie biorąc pod uwagę koszty związane z uruchomieniem nowego procesu w niektórych systemach operacyjnych. Mamy serwery z 32 rdzeniami, więc do pełnego wykorzystania ich w CPython potrzebowałbym 32 procesów. To nie jest „dobre rozwiązanie”, to hack, aby obejść niedociągnięcia CPython.
Podstawowy

8
Fakt, że wątki istnieją na platformach innych niż Windows, powinien być wystarczającym dowodem na to, że rozwidlenie nie jest odpowiednie w każdej sytuacji.
zneak

42

Po pierwsze: Python nie ma GIL. Python jest językiem programowania. Język programowania to zbiór abstrakcyjnych reguł i ograniczeń matematycznych. W specyfikacji języka Python nie ma nic, co mówi, że musi istnieć GIL.

Istnieje wiele różnych implementacji języka Python. Niektóre mają GIL, niektóre nie.

Jednym prostym wytłumaczeniem posiadania GIL jest to, że pisanie współbieżnego kodu jest trudne. Umieszczając olbrzymi zamek wokół kodu, zmuszasz go do ciągłego działania szeregowego. Problem rozwiązany!

W szczególności w CPython jednym ważnym celem jest ułatwienie rozszerzenia interpretera o wtyczki napisane w C. Ponownie pisanie współbieżnego kodu jest trudne, więc gwarantując, że nie będzie współbieżności, ułatwia pisanie rozszerzeń dla tłumacz. Co więcej, wiele z tych rozszerzeń to tylko cienkie opakowania wokół istniejących bibliotek, które mogły nie zostać napisane z myślą o współbieżności.


6
To ten sam argument, co brak braku jawnych typów liczbowych w Javie - programiści uważają, że wszyscy inni są głupsi niż oni ...
Podstawowy

1
@Basic - wierz lub nie, nawet jeśli nie jesteś naprawdę, naprawdę głupi, okazuje się, że posiadanie języka, który upraszcza założenia, co oznacza, że ​​nie myślisz o pewnych rzeczach, aby mogły działać, nadal jest przydatny rzecz. CPython jest świetny do niektórych rzeczy, w tym do prostych aplikacji wielowątkowych (gdzie program jest związany z IO, których wiele jest, a zatem GIL nie ma znaczenia), ponieważ decyzje projektowe, które uczyniły GIL najlepszym rozwiązaniem, również ułatwiają programowanie tych aplikacji , w szczególności fakt, że obsługuje operacje atomowe na kolekcjach .
Jules

@Jules Tak, jest to bardzo przydatne, dopóki nie potrzebujesz tych możliwości. „preferowane” rozwiązanie cpython „po prostu napisz to w innym języku, takim jak c ++”, oznacza to, że tracisz każdą korzyść z pojedynczego pytania w Pythonie. Jeśli piszesz połowę kodu w c ++, to po co zaczynać od Pythona? Jasne, w przypadku małych projektów API / klejów jest to szybkie i łatwe, a w przypadku ETL nie ma sobie równych, ale nie nadaje się do niczego, co wymaga ciężkiego podnoszenia. To samo, co używanie Javy do komunikacji ze sprzętem ... To prawie komiczne obręcz, przez które musisz skakać.
Podstawowy

16

Jaki jest cel GIL?

Dokumentacja CAPI ma do powiedzenia na ten temat:

Interpreter języka Python nie jest w pełni bezpieczny dla wątków. Aby obsługiwać wielowątkowe programy w języku Python, istnieje globalna blokada, zwana globalną blokadą interpretera lub GIL, którą musi przytrzymać bieżący wątek, aby mógł bezpiecznie uzyskać dostęp do obiektów Pythona. Bez blokady nawet najprostsze operacje mogą powodować problemy w programie wielowątkowym: na przykład, gdy dwa wątki jednocześnie zwiększają liczbę referencji tego samego obiektu, liczba referencji może być zwiększana tylko raz zamiast dwa razy.

Innymi słowy, GIL zapobiega korupcji państwa. Programy w języku Python nigdy nie powinny powodować błędu segmentacji, ponieważ dozwolone są tylko operacje bezpieczne dla pamięci. GIL rozszerza tę gwarancję na programy wielowątkowe.

Jakie są alternatywy?

Jeśli celem GIL jest ochrona państwa przed korupcją, wówczas jedną oczywistą alternatywą jest zamknięcie się na znacznie drobniejszym ziarnie; być może na poziomie obiektu. Problem polega na tym, że chociaż wykazano, że zwiększa wydajność programów wielowątkowych, ma w związku z tym więcej programów ogólnych i jednowątkowych.


2
Byłoby wspaniale, gdyby użytkownik uruchomił program z opcją interpretera zastępującą gil dla drobnoziarnistego zamka i w jakiś sposób wiedział - tylko do odczytu - czy bieżący proces został wywołany z gilem, czy bez.
Luis Masuelli,

Pomimo GIL udało mi się wygenerować błąd segmentacji w programie wielowątkowym z powodu nieostrożnego użycia modułu pyodbc. Dlatego „błędem segmentacji nigdy nie powinno być”.
Muposat
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.