Was ist eine globale Interpretersperre und warum ist sie ein Problem?
Beim Entfernen der GIL aus Python wurde viel Lärm gemacht, und ich würde gerne verstehen, warum das so wichtig ist. Ich habe selbst noch nie einen Compiler oder einen Interpreter geschrieben. Seien Sie also nicht sparsam mit Details, ich werde sie wahrscheinlich brauchen, um sie zu verstehen.
python
python-internals
gil
e-satis
quelle
quelle
Antworten:
Pythons GIL soll den Zugriff auf Interpreter-Interna aus verschiedenen Threads serialisieren. Auf Mehrkernsystemen bedeutet dies, dass mehrere Threads mehrere Kerne nicht effektiv nutzen können. (Wenn die GIL nicht zu diesem Problem geführt hätte, würden sich die meisten Menschen nicht für die GIL interessieren - sie wird nur aufgrund der zunehmenden Verbreitung von Mehrkernsystemen als Problem angesprochen.) Wenn Sie sie im Detail verstehen möchten, Sie können dieses Video ansehen oder sich diese Folien ansehen . Es könnten zu viele Informationen sein, aber dann haben Sie nach Details gefragt :-)
Beachten Sie, dass Pythons GIL nur für CPython, die Referenzimplementierung, wirklich ein Problem darstellt. Jython und IronPython haben keine GIL. Als Python-Entwickler stoßen Sie im Allgemeinen nur dann auf die GIL, wenn Sie eine C-Erweiterung schreiben. C-Erweiterungsschreiber müssen die GIL freigeben, wenn ihre Erweiterungen E / A blockieren, damit andere Threads im Python-Prozess ausgeführt werden können.
quelle
regex
,lxml
,numpy
Module. Cython erlaubt es, GIL in benutzerdefiniertem Code freizugeben, zBb2a_bin(data)
Angenommen, Sie haben mehrere Threads, die die Daten des anderen nicht wirklich berühren. Diese sollten so unabhängig wie möglich ausgeführt werden. Wenn Sie eine "globale Sperre" haben, die Sie erwerben müssen, um (sagen wir) eine Funktion aufzurufen, kann dies zu einem Engpass führen. Es kann sein, dass Sie nicht viel davon profitieren, wenn Sie überhaupt mehrere Threads haben.
Um es in eine reale Analogie zu bringen: Stellen Sie sich 100 Entwickler vor, die in einem Unternehmen mit nur einer einzigen Kaffeetasse arbeiten. Die meisten Entwickler verbrachten ihre Zeit damit, auf Kaffee zu warten, anstatt zu codieren.
Nichts davon ist Python-spezifisch - ich weiß nicht genau, wofür Python überhaupt eine GIL benötigte. Hoffentlich erhalten Sie jedoch eine bessere Vorstellung vom allgemeinen Konzept.
quelle
Lassen Sie uns zunächst verstehen, was die Python-GIL bietet:
Jede Operation / Anweisung wird im Interpreter ausgeführt. GIL stellt sicher, dass der Interpreter zu einem bestimmten Zeitpunkt von einem einzelnen Thread gehalten wird . Und Ihr Python-Programm mit mehreren Threads funktioniert in einem einzigen Interpreter. Zu einem bestimmten Zeitpunkt wird dieser Interpreter von einem einzelnen Thread gehalten. Es bedeutet , dass nur der Thread, der den Interpreter hält , wird ausgeführt auf jedem Zeitpunkt .
Warum ist das ein Problem?
Ihre Maschine verfügt möglicherweise über mehrere Kerne / Prozessoren. Mehrere Kerne ermöglichen die gleichzeitige Ausführung mehrerer Threads, dh, mehrere Threads können zu einem bestimmten Zeitpunkt ausgeführt werden. . Da der Interpreter jedoch von einem einzelnen Thread gehalten wird, tun andere Threads nichts, obwohl sie Zugriff auf einen Kern haben. Sie erhalten also keinen Vorteil durch mehrere Kerne, da zu jedem Zeitpunkt nur ein einziger Kern verwendet wird, der der Kern ist, der von dem Thread verwendet wird, der derzeit den Interpreter enthält. Die Ausführung Ihres Programms dauert also so lange, als wäre es ein einzelnes Thread-Programm.
Potenziell blockierende oder lang laufende Vorgänge wie E / A, Bildverarbeitung und NumPy-Nummernverknüpfung treten jedoch außerhalb der GIL auf. Von hier genommen . Für solche Operationen ist eine Multithread-Operation trotz des Vorhandenseins von GIL immer noch schneller als eine Single-Threaded-Operation. GIL ist also nicht immer ein Engpass.
Bearbeiten: GIL ist ein Implementierungsdetail von CPython. IronPython und Jython haben kein GIL, daher sollte ein wirklich Multithread-Programm in ihnen möglich sein, obwohl ich PyPy und Jython nie verwendet habe und mir dessen nicht sicher bin.
quelle
Python erlaubt kein Multithreading im wahrsten Sinne des Wortes. Es verfügt über ein Multithreading-Paket. Wenn Sie jedoch Multithreading-Pakete verwenden möchten, um Ihren Code zu beschleunigen, ist es normalerweise keine gute Idee, es zu verwenden. Python hat ein Konstrukt namens Global Interpreter Lock (GIL).
https://www.youtube.com/watch?v=ph374fJqFPE
Die GIL stellt sicher, dass immer nur einer Ihrer 'Threads' gleichzeitig ausgeführt werden kann. Ein Thread erwirbt die GIL, erledigt ein wenig Arbeit und leitet die GIL dann an den nächsten Thread weiter. Dies geschieht sehr schnell, so dass es für das menschliche Auge so aussieht, als würden Ihre Threads parallel ausgeführt, aber sie wechseln sich nur mit demselben CPU-Kern ab. All diese GIL-Übergaben erhöhen den Aufwand für die Ausführung. Dies bedeutet, dass die Verwendung des Threading-Pakets häufig keine gute Idee ist, wenn Sie Ihren Code schneller ausführen möchten.
Es gibt Gründe, das Threading-Paket von Python zu verwenden. Wenn Sie einige Dinge gleichzeitig ausführen möchten und Effizienz kein Problem darstellt, ist dies völlig in Ordnung und praktisch. Oder wenn Sie Code ausführen, der auf etwas warten muss (wie z. B. eine E / A), kann dies sehr sinnvoll sein. In der Threading-Bibliothek können Sie jedoch keine zusätzlichen CPU-Kerne verwenden.
Multithreading kann an das Betriebssystem ausgelagert werden (durch Multiverarbeitung), an eine externe Anwendung, die Ihren Python-Code aufruft (z. B. Spark oder Hadoop), oder an Code, den Ihr Python-Code aufruft (z. B. Sie könnten Ihren Python haben Code ruft eine C-Funktion auf, die die teuren Multithread-Aufgaben erledigt).
quelle
Immer wenn zwei Threads auf dieselbe Variable zugreifen, tritt ein Problem auf. In C ++ besteht die Möglichkeit, das Problem zu vermeiden, darin, eine Mutex-Sperre zu definieren, um zu verhindern, dass zwei Threads gleichzeitig den Setter eines Objekts eingeben.
Multithreading ist in Python möglich, aber zwei Threads können nicht gleichzeitig mit einer Granularität ausgeführt werden, die feiner als eine Python-Anweisung ist. Der laufende Thread erhält eine globale Sperre namens GIL.
Dies bedeutet, wenn Sie mit dem Schreiben von Multithread-Code beginnen, um die Vorteile Ihres Multicore-Prozessors zu nutzen, wird sich Ihre Leistung nicht verbessern. Die übliche Problemumgehung besteht darin, mehrere Prozesse auszuführen.
Beachten Sie, dass es möglich ist, die GIL freizugeben, wenn Sie sich in einer Methode befinden, die Sie beispielsweise in C geschrieben haben.
Die Verwendung einer GIL ist Python nicht eigen, sondern einigen seiner Interpreter, einschließlich des am häufigsten verwendeten CPython. (#edited, siehe Kommentar)
Das GIL-Problem ist in Python 3000 weiterhin gültig.
quelle
Python 3.7-Dokumentation
Ich möchte auch das folgende Zitat aus der Python-
threading
Dokumentation hervorheben :Dieser Link verweist auf den Glossareintrag, in
global interpreter lock
dem erklärt wird, dass die GIL impliziert, dass Thread-Parallelität in Python für CPU-gebundene Aufgaben ungeeignet ist :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 derthreading
folgenden ähnelt :Und die Dokumente für
concurrent.futures.ProcessPoolExecutor
erklären, dass esmultiprocessing
als Backend verwendet:Dies sollte im Gegensatz zu der anderen Basisklasse stehen
ThreadPoolExecutor
, die Threads anstelle von Prozessen verwendetDaraus schließen wir, dass dies
ThreadPoolExecutor
nur für E / A-gebundene Aufgaben geeignet ist, währendProcessPoolExecutor
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:
quelle
Warum Python (CPython und andere) die GIL verwendet
Von http://wiki.python.org/moin/GlobalInterpreterLock
In CPython ist die globale Interpretersperre (GIL) ein Mutex, der verhindert, dass mehrere native Threads Python-Bytecodes gleichzeitig ausführen. Diese Sperre ist hauptsächlich erforderlich, weil die Speicherverwaltung von CPython nicht threadsicher ist.
Wie entferne ich es aus Python?
Wie Lua könnte Python vielleicht mehrere VMs starten, aber Python macht das nicht, ich denke, es sollte noch andere Gründe geben.
In Numpy oder einer anderen erweiterten Python-Bibliothek kann die Freigabe der GIL für andere Threads manchmal die Effizienz des gesamten Programms steigern.
quelle
Ich möchte ein Beispiel aus dem Buch Multithreading für visuelle Effekte teilen. Hier ist also eine klassische Deadlock-Situation
Betrachten Sie nun die Ereignisse in der Sequenz, die zu einem Deadlock führen.
quelle