Was genau ist die Funktion von Pythons Global Interpreter Lock? Verwenden andere Sprachen, die zu Bytecode kompiliert wurden, einen ähnlichen Mechanismus?
Was genau ist die Funktion von Pythons Global Interpreter Lock? Verwenden andere Sprachen, die zu Bytecode kompiliert wurden, einen ähnlichen Mechanismus?
Antworten:
Im Allgemeinen müssen Sie für alle Thread-Sicherheitsprobleme Ihre internen Datenstrukturen mit Sperren schützen. Dies kann mit verschiedenen Granularitätsstufen erfolgen.
Sie können eine feinkörnige Verriegelung verwenden, bei der jede einzelne Struktur eine eigene Verriegelung hat.
Sie können eine grobkörnige Verriegelung verwenden, bei der eine Verriegelung alles schützt (GIL-Ansatz).
Für jede Methode gibt es verschiedene Vor- und Nachteile. Feinkörniges Sperren ermöglicht eine größere Parallelität - zwei Threads können parallel ausgeführt werden, wenn sie keine Ressourcen gemeinsam nutzen. Es gibt jedoch einen viel größeren Verwaltungsaufwand. Für jede Codezeile müssen Sie möglicherweise mehrere Sperren erwerben und freigeben.
Der grobkörnige Ansatz ist das Gegenteil. Zwei Threads können nicht gleichzeitig ausgeführt werden, aber ein einzelner Thread wird schneller ausgeführt, da er nicht so viel Buchhaltung betreibt. Letztendlich kommt es auf einen Kompromiss zwischen Single-Threaded-Geschwindigkeit und Parallelität an.
Es gab einige Versuche, die GIL in Python zu entfernen, aber der zusätzliche Aufwand für Single-Threaded-Maschinen war im Allgemeinen zu groß. Einige Fälle können sogar auf Multiprozessor-Computern aufgrund von Sperrenkonflikten langsamer sein.
Verwenden andere Sprachen, die zu Bytecode kompiliert wurden, einen ähnlichen Mechanismus?
Es variiert und sollte wahrscheinlich nicht als Spracheigenschaft, sondern als Implementierungseigenschaft betrachtet werden. Beispielsweise gibt es Python-Implementierungen wie Jython und IronPython, die den Threading-Ansatz der zugrunde liegenden VM anstelle eines GIL-Ansatzes verwenden. Darüber hinaus sieht die nächste Version von Ruby zu bewegen in Richtung einer GIL einzuführen.
Folgendes stammt aus dem offiziellen Python / C-API-Referenzhandbuch :
Der Python-Interpreter ist nicht vollständig threadsicher. Um Python-Programme mit mehreren Threads zu unterstützen, muss der aktuelle Thread eine globale Sperre aufrechterhalten, bevor er sicher auf Python-Objekte zugreifen kann. Ohne die Sperre können selbst die einfachsten Vorgänge Probleme in einem Multithread-Programm verursachen: Wenn beispielsweise zwei Threads gleichzeitig den Referenzzähler desselben Objekts erhöhen, wird der Referenzzähler möglicherweise nur einmal statt zweimal erhöht.
Daher besteht die Regel, dass nur der Thread, der die globale Interpretersperre erhalten hat, Python-Objekte bearbeiten oder Python / C-API-Funktionen aufrufen darf. Um Python-Programme mit mehreren Threads zu unterstützen, gibt der Interpreter die Sperre regelmäßig frei und ruft sie erneut ab - standardmäßig alle 100 Bytecode-Anweisungen (dies kann mit sys.setcheckinterval () geändert werden). Die Sperre wird auch aufgehoben und erneut angefordert, um möglicherweise E / A-Vorgänge wie das Lesen oder Schreiben einer Datei zu blockieren, sodass andere Threads ausgeführt werden können, während der Thread, der die E / A anfordert, auf den Abschluss des E / A-Vorgangs wartet.
Ich denke, es fasst das Problem ziemlich gut zusammen.
Die globale Interpreter-Sperre ist eine große Mutex-Sperre, die Referenzzähler vor dem Abspritzen schützt. Wenn Sie reinen Python-Code schreiben, geschieht dies alles hinter den Kulissen. Wenn Sie jedoch Python in C einbetten, müssen Sie möglicherweise die Sperre explizit aufheben / aufheben.
Dieser Mechanismus hängt nicht damit zusammen, dass Python zu Bytecode kompiliert wird. Es wird für Java nicht benötigt. Tatsächlich wird es nicht einmal für Jython benötigt (Python kompiliert zu jvm).
siehe auch diese Frage
Python wurde wie Perl 5 nicht von Grund auf als threadsicher entwickelt. Threads wurden nachträglich aufgepfropft, sodass die globale Interpreter-Sperre verwendet wird, um den gegenseitigen Ausschluss aufrechtzuerhalten, wenn zu einem bestimmten Zeitpunkt nur ein Thread Code im Darm des Interpreters ausführt.
Einzelne Python-Threads werden vom Interpreter selbst kooperativ multitasking ausgeführt, indem die Sperre von Zeit zu Zeit gewechselt wird.
Wenn Sie mit Python von C aus sprechen, wenn andere Python-Threads aktiv sind, um sich für dieses Protokoll zu entscheiden und sicherzustellen, dass hinter Ihrem Rücken nichts Unsicheres passiert, müssen Sie die Sperre selbst aktivieren.
Andere Systeme mit einem Single-Thread-Erbe, das sich später zu Mulithread-Systemen entwickelte, verfügen häufig über einen solchen Mechanismus. Zum Beispiel hat der Linux-Kernel die "Big Kernel Lock" aus seinen frühen SMP-Tagen. Mit der Zeit wird die Multithreading-Leistung allmählich zu einem Problem. Daher besteht die Tendenz, diese Art von Sperren in kleinere Teile zu zerlegen oder sie nach Möglichkeit durch sperrfreie Algorithmen und Datenstrukturen zu ersetzen, um den Durchsatz zu maximieren.
reiserfs
- der einzige wirkliche Grund, warum ich überhaupt davon weiß).
In Bezug auf Ihre zweite Frage verwenden dies nicht alle Skriptsprachen, aber es macht sie nur weniger leistungsfähig. Zum Beispiel sind die Threads in Ruby grün und nicht nativ.
In Python sind die Threads nativ und die GIL verhindert nur, dass sie auf verschiedenen Kernen ausgeführt werden.
In Perl sind die Threads noch schlechter. Sie kopieren nur den gesamten Interpreter und sind bei weitem nicht so benutzerfreundlich wie in Python.
Vielleicht hilft dieser Artikel der BDFL.