Dokumentacja Python 3.7
Chciałbym również podkreślić następujący cytat z dokumentacji Pythonathreading
:
Szczegóły implementacji CPython: W CPython, z powodu globalnej blokady interpretera, tylko jeden wątek może wykonać kod Pythona jednocześnie (nawet jeśli niektóre biblioteki zorientowane na wydajność mogą obejść to ograniczenie). Jeśli chcesz, aby aplikacja lepiej wykorzystywała zasoby obliczeniowe maszyn wielordzeniowych, zalecamy użycie multiprocessing
lub concurrent.futures.ProcessPoolExecutor
. Jednak wątkowanie jest nadal odpowiednim modelem, jeśli chcesz uruchamiać wiele zadań związanych z operacjami we / wy jednocześnie.
To łącze do pozycji Glosariusz, wglobal interpreter lock
której wyjaśniono, że GIL sugeruje, że równoległość wątkowa w Pythonie jest nieodpowiednia do zadań związanych z procesorem :
Mechanizm używany przez interpreter CPython w celu zapewnienia, że tylko jeden wątek wykonuje kod bajtowy Pythona jednocześnie. Upraszcza to implementację CPython, czyniąc model obiektowy (w tym krytyczne typy wbudowane, takie jak dict), domyślnie zabezpieczony przed równoczesnym dostępem. Zablokowanie całego interpretera ułatwia interpreterowi wielowątkowość kosztem dużej równoległości zapewnianej przez maszyny wieloprocesorowe.
Jednak niektóre moduły rozszerzeń, standardowe lub zewnętrzne, zostały zaprojektowane tak, aby zwolnić GIL podczas wykonywania zadań wymagających dużej mocy obliczeniowej, takich jak kompresja lub mieszanie. Ponadto GIL jest zawsze zwalniany podczas wykonywania operacji we / wy.
Dotychczasowe wysiłki w celu stworzenia interpretera „bez wątków” (takiego, który blokuje współdzielone dane z większą szczegółowością) nie powiodły się, ponieważ w zwykłym przypadku jednoprocesorowym wydajność spadła. Uważa się, że przezwyciężenie tego problemu z wydajnością spowodowałoby, że wdrożenie byłoby znacznie bardziej skomplikowane, a zatem kosztowne w utrzymaniu.
Ten cytat sugeruje również, że dyktowania, a tym samym przypisywanie zmiennych, są również wątkowo bezpieczne jako szczegóły implementacji CPython:
Następnie dokumentacja multiprocessing
pakietu wyjaśnia, w jaki sposób pokonuje GIL poprzez proces odradzania, ujawniając interfejs podobny do threading
:
multiprocessing to pakiet, który obsługuje procesy odradzania przy użyciu interfejsu API podobnego do modułu wątków. Pakiet wieloprocesowy oferuje zarówno lokalną, jak i zdalną współbieżność, skutecznie omijając blokadę globalnego interpretera, używając podprocesów zamiast wątków. Z tego powodu moduł wieloprocesowy pozwala programiście w pełni wykorzystać wiele procesorów na danym komputerze. Działa zarówno w systemie Unix, jak i Windows.
I dokumentacja dlaconcurrent.futures.ProcessPoolExecutor
wyjaśnienia, że wykorzystuje multiprocessing
jako backend:
Klasa ProcessPoolExecutor jest podklasą Executora, która wykorzystuje pulę procesów do asynchronicznego wykonywania wywołań. ProcessPoolExecutor wykorzystuje moduł wieloprocesowy, który pozwala mu przejść obok globalnej blokady interpretera, ale oznacza również, że można wykonywać i zwracać tylko obiekty do wyboru.
które powinny być skontrastowane z inną klasą bazową, ThreadPoolExecutor
która używa wątków zamiast procesów
ThreadPoolExecutor jest podklasą Executora, która wykorzystuje pulę wątków do asynchronicznego wykonywania wywołań.
z którego dochodzimy do wniosku, że ThreadPoolExecutor
jest odpowiedni tylko do zadań związanych z We / Wy, a jednocześnie ProcessPoolExecutor
może obsługiwać zadania związane z procesorem.
Poniższe pytanie dotyczy przede wszystkim tego, dlaczego GIL istnieje: Dlaczego blokada globalnego interpretera?
Eksperymenty procesowe a wątkowe
W Multiprocessing vs Threading Python przeprowadziłem eksperymentalną analizę procesu vs wątków w Pythonie.
Szybki podgląd wyników: