Python 3.7-Dokumentation
Ich möchte auch das folgende Zitat aus der Python- threading
Dokumentation hervorheben :
Details zur CPython-Implementierung: In CPython kann aufgrund der globalen Interpreter-Sperre nur ein Thread Python-Code gleichzeitig ausführen (obwohl bestimmte leistungsorientierte Bibliotheken diese Einschränkung möglicherweise überwinden). Wenn Sie möchten, dass Ihre Anwendung die Rechenressourcen von Mehrkernmaschinen besser nutzt, wird empfohlen, multiprocessing
oder zu verwenden concurrent.futures.ProcessPoolExecutor
. Threading ist jedoch immer noch ein geeignetes Modell, wenn Sie mehrere E / A-gebundene Aufgaben gleichzeitig ausführen möchten.
Dieser Link verweist auf den Glossareintrag, inglobal interpreter lock
dem erklärt wird, dass die GIL impliziert, dass Thread-Parallelität in Python für CPU-gebundene Aufgaben ungeeignet ist :
Der Mechanismus, der vom CPython-Interpreter verwendet wird, um sicherzustellen, dass jeweils nur ein Thread Python-Bytecode ausführt. Dies vereinfacht die CPython-Implementierung, indem das Objektmodell (einschließlich kritischer integrierter Typen wie dict) implizit vor gleichzeitigem Zugriff geschützt wird. Das Sperren des gesamten Interpreters erleichtert das Multithreading des Interpreters auf Kosten eines Großteils der Parallelität, die Multiprozessor-Maschinen bieten.
Einige Erweiterungsmodule, entweder Standardmodule oder Module von Drittanbietern, sind jedoch so konzipiert, dass sie die GIL freigeben, wenn rechenintensive Aufgaben wie Komprimierung oder Hashing ausgeführt werden. Außerdem wird die GIL immer freigegeben, wenn E / A ausgeführt wird.
Frühere Bemühungen, einen "Free-Threaded" -Interpreter zu erstellen (der gemeinsam genutzte Daten mit einer viel feineren Granularität sperrt), waren nicht erfolgreich, da die Leistung im Fall eines herkömmlichen Einzelprozessors darunter litt. Es wird angenommen, dass die Überwindung dieses Leistungsproblems die Implementierung viel komplizierter und daher kostspieliger in der Wartung machen würde.
Dieses Zitat impliziert auch, dass Dikte und damit die Variablenzuweisung als CPython-Implementierungsdetail auch threadsicher sind:
Als Nächstes wird in den Dokumenten für das multiprocessing
Paket erläutert, wie die GIL durch den Spawning-Prozess überwunden wird, während eine Schnittstelle verfügbar gemacht wird, die der threading
folgenden ähnelt :
Multiprocessing ist ein Paket, das Spawning-Prozesse mithilfe einer API unterstützt, die dem Threading-Modul ähnelt. Das Multiprocessing-Paket bietet sowohl lokale als auch Remote-Parallelität und umgeht die globale Interpreter-Sperre effektiv, indem Subprozesse anstelle von Threads verwendet werden. Aus diesem Grund ermöglicht das Multiprozessor-Modul dem Programmierer, mehrere Prozessoren auf einer bestimmten Maschine vollständig zu nutzen. Es läuft sowohl unter Unix als auch unter Windows.
Und die Dokumente fürconcurrent.futures.ProcessPoolExecutor
erklären, dass es multiprocessing
als Backend verwendet:
Die ProcessPoolExecutor-Klasse ist eine Executor-Unterklasse, die einen Pool von Prozessen verwendet, um Aufrufe asynchron auszuführen. ProcessPoolExecutor verwendet das Multiprocessing-Modul, mit dem die globale Interpreter-Sperre umgangen werden kann, aber auch, dass nur auswählbare Objekte ausgeführt und zurückgegeben werden können.
Dies sollte im Gegensatz zu der anderen Basisklasse stehen ThreadPoolExecutor
, die Threads anstelle von Prozessen verwendet
ThreadPoolExecutor ist eine Executor-Unterklasse, die einen Pool von Threads verwendet, um Aufrufe asynchron auszuführen.
Daraus schließen wir, dass dies ThreadPoolExecutor
nur für E / A-gebundene Aufgaben geeignet ist, während ProcessPoolExecutor
es auch CPU-gebundene Aufgaben verarbeiten kann.
Die folgende Frage fragt, warum die GIL überhaupt existiert: Warum die globale Interpretersperre?
Prozess gegen Thread-Experimente
Bei Multiprocessing vs Threading Python habe ich eine experimentelle Analyse von Process vs Threads in Python durchgeführt.
Schnelle Vorschau der Ergebnisse: