Jaka jest dokładnie funkcja globalnej blokady interpretera języka Python? Czy inne języki, które są kompilowane do kodu bajtowego, wykorzystują podobny mechanizm?
Jaka jest dokładnie funkcja globalnej blokady interpretera języka Python? Czy inne języki, które są kompilowane do kodu bajtowego, wykorzystują podobny mechanizm?
Odpowiedzi:
Ogólnie rzecz biorąc, w przypadku każdego problemu związanego z bezpieczeństwem wątków konieczne będzie zabezpieczenie wewnętrznych struktur danych za pomocą blokad. Można to zrobić na różnych poziomach szczegółowości.
Możesz użyć blokowania drobnoziarnistego, w którym każda oddzielna konstrukcja ma swój własny zamek.
Możesz użyć blokowania gruboziarnistego, w którym jeden zamek chroni wszystko (podejście GIL).
Każda metoda ma różne zalety i wady. Drobnoziarniste blokowanie umożliwia większą równoległość - dwa wątki mogą być wykonywane równolegle, gdy nie współużytkują żadnych zasobów. Istnieje jednak dużo większe obciążenie administracyjne. Dla każdego wiersza kodu może być konieczne nabycie i zwolnienie kilku blokad.
Podejście gruboziarniste jest odwrotne. Dwa wątki nie mogą działać w tym samym czasie, ale pojedynczy wątek będzie działał szybciej, ponieważ nie zajmuje się tak dużą księgowością. Ostatecznie sprowadza się to do kompromisu między szybkością jednowątkową a równoległością.
Było kilka prób usunięcia GIL w Pythonie, ale dodatkowe obciążenie dla maszyn jednowątkowych było generalnie zbyt duże. Niektóre przypadki mogą być faktycznie wolniejsze nawet na maszynach wieloprocesorowych z powodu rywalizacji o blokady.
Czy inne języki, które są kompilowane do kodu bajtowego, wykorzystują podobny mechanizm?
Różni się i prawdopodobnie nie powinno być uważane za właściwość języka, a raczej za właściwość implementacji. Na przykład istnieją implementacje Pythona, takie jak Jython i IronPython, które wykorzystują podejście wątkowe ich bazowej maszyny wirtualnej zamiast podejścia GIL. Dodatkowo wygląda na to, że następna wersja Rubiego zmierza w kierunku wprowadzenia GIL.
Poniższy tekst pochodzi z oficjalnej instrukcji obsługi interfejsu API języka Python / C :
Interpreter Pythona nie jest w pełni bezpieczny dla wątków. Aby obsługiwać wielowątkowe programy w Pythonie, istnieje globalna blokada, która musi być utrzymywana przez bieżący wątek, zanim będzie mógł bezpiecznie uzyskać dostęp do obiektów Pythona. Bez blokady nawet najprostsze operacje mogłyby powodować problemy w programie wielowątkowym: na przykład, gdy dwa wątki jednocześnie zwiększają liczbę odwołań do tego samego obiektu, liczba odwołań mogłaby zostać zwiększona tylko raz zamiast dwukrotnie.
Dlatego istnieje reguła, że tylko wątek, który uzyskał globalną blokadę interpretera, może działać na obiektach Pythona lub wywoływać funkcje API Python / C. Aby obsługiwać wielowątkowe programy w Pythonie, interpreter regularnie zwalnia i ponownie przejmuje blokadę - domyślnie co 100 instrukcji kodu bajtowego (można to zmienić za pomocą sys.setcheckinterval ()). Blokada jest również zwalniana i ponownie uzyskiwana wokół potencjalnie blokujących operacji we / wy, takich jak odczyt lub zapis pliku, dzięki czemu inne wątki mogą działać, gdy wątek żądający operacji we / wy oczekuje na zakończenie operacji we / wy.
Myślę, że to całkiem dobrze podsumowuje problem.
Globalna blokada interpretera to duża blokada typu mutex, która chroni liczniki referencyjne przed podłączeniem. Jeśli piszesz czysty kod Pythona, to wszystko dzieje się za kulisami, ale jeśli osadzasz Python w C, być może będziesz musiał jawnie wziąć / zwolnić blokadę.
Ten mechanizm nie jest związany z kompilacją Pythona do kodu bajtowego. Nie jest to potrzebne w Javie. W rzeczywistości nie jest to nawet potrzebne dla Jythona (python skompilowany do jvm).
zobacz także to pytanie
Python, podobnie jak Perl 5, nie został zaprojektowany od podstaw, aby był bezpieczny dla wątków. Wątki zostały zaszczepione po fakcie, więc globalna blokada interpretera służy do utrzymania wzajemnego wykluczenia, gdy tylko jeden wątek wykonuje kod w danym momencie w trzewiach interpretera.
Poszczególne wątki Pythona są wspólnie wielozadaniowe przez samego tłumacza poprzez cykliczne włączanie blokady co jakiś czas.
Samodzielne chwycenie blokady jest potrzebne, gdy rozmawiasz z Pythonem z C, gdy inne wątki Pythona są aktywne, aby „włączyć się” do tego protokołu i upewnić się, że za Twoimi plecami nie dzieje się nic niebezpiecznego.
Inne systemy, które mają jednowątkowe dziedzictwo, które później przekształciły się w systemy wielowątkowe, często mają taki mechanizm. Na przykład jądro Linuksa ma „Big Kernel Lock” od wczesnych dni SMP. Stopniowo w miarę upływu czasu, gdy wydajność wielowątkowości staje się problemem, istnieje tendencja do podejmowania prób rozbijania tego rodzaju blokad na mniejsze części lub zastępowania ich tam, gdzie to możliwe, algorytmami i strukturami danych bez blokad, aby zmaksymalizować przepustowość.
reiserfs
- jedyny prawdziwy powód, dla którego w ogóle o tym wiem).
Jeśli chodzi o drugie pytanie, nie wszystkie języki skryptowe tego używają, ale tylko zmniejsza ich możliwości. Na przykład wątki w Rubim są zielone, a nie natywne.
W Pythonie wątki są natywne, a GIL zapobiega tylko ich działaniu na różnych rdzeniach.
W Perlu wątki są jeszcze gorsze. Po prostu kopiują cały interpreter i nie są tak użyteczne jak w Pythonie.
Może ten artykuł BDFL pomoże.