Ich habe versucht, mich mit der Funktionsweise von Threads in Python zu beschäftigen, und es ist schwierig, gute Informationen über deren Funktionsweise zu finden. Ich vermisse vielleicht nur einen Link oder so, aber es scheint, dass die offizielle Dokumentation zu diesem Thema nicht sehr gründlich ist und ich keine gute Zusammenfassung finden konnte.
Soweit ich weiß, kann nur ein Thread gleichzeitig ausgeführt werden, und der aktive Thread wechselt alle 10 Anweisungen oder so?
Wo gibt es eine gute Erklärung oder können Sie eine liefern? Es wäre auch sehr schön, sich der häufigen Probleme bewusst zu sein, auf die Sie bei der Verwendung von Threads mit Python stoßen.
Python ist eine ziemlich einfach zu fädelnde Sprache, aber es gibt einige Einschränkungen. Das Wichtigste, was Sie wissen müssen, ist das Global Interpreter Lock. Dadurch kann nur ein Thread auf den Interpreter zugreifen. Dies bedeutet zwei Dinge: 1) Sie verwenden selten eine Lock-Anweisung in Python und 2) Wenn Sie Multiprozessorsysteme nutzen möchten, müssen Sie separate Prozesse verwenden. EDIT: Ich sollte auch darauf hinweisen, dass Sie einen Teil des Codes in C / C ++ einfügen können, wenn Sie auch die GIL umgehen möchten.
Daher müssen Sie überlegen, warum Sie Threads verwenden möchten. Wenn Sie Ihre App parallelisieren möchten, um die Dual-Core-Architektur zu nutzen, müssen Sie in Betracht ziehen, Ihre App in mehrere Prozesse aufzuteilen.
Wenn Sie die Reaktionsfähigkeit verbessern möchten, sollten Sie die Verwendung von Threads in Betracht ziehen. Es gibt jedoch auch andere Alternativen, nämlich Mikrothreading . Es gibt auch einige Frameworks, die Sie untersuchen sollten:
quelle
Unten finden Sie ein grundlegendes Threading-Beispiel. Es werden 20 Threads erzeugt; Jeder Thread gibt seine Thread-Nummer aus. Führen Sie es aus und beobachten Sie die Reihenfolge, in der sie gedruckt werden.
Wie Sie bereits angedeutet haben, werden Python-Threads durch Time-Slicing implementiert. So erhalten sie den "parallelen" Effekt.
In meinem Beispiel erweitert meine Foo-Klasse den Thread. Anschließend implementiere ich die
run
Methode. Dort wird der Code abgelegt, den Sie in einem Thread ausführen möchten. Um den Thread zu starten, rufen Siestart()
das Thread-Objekt auf, das automatisch dierun
Methode aufruft ...Dies sind natürlich nur die Grundlagen. Möglicherweise möchten Sie mehr über Semaphoren, Mutexe und Sperren für die Thread-Synchronisierung und die Nachrichtenübermittlung erfahren.
quelle
Verwenden Sie Threads in Python, wenn die einzelnen Worker E / A-gebundene Operationen ausführen. Wenn Sie versuchen, über mehrere Kerne auf einem Computer zu skalieren, finden Sie entweder ein gutes IPC- Framework für Python oder wählen Sie eine andere Sprache.
quelle
Hinweis: Wo immer ich erwähne,
thread
meine ich speziell Threads in Python, bis dies ausdrücklich angegeben wird.Threads funktionieren in Python etwas anders, wenn Sie aus dem
C/C++
Hintergrund kommen. In Python kann zu einem bestimmten Zeitpunkt nur ein Thread ausgeführt werden. Dies bedeutet, dass Threads in Python die Leistung mehrerer Verarbeitungskerne nicht wirklich nutzen können, da Threads aufgrund ihres Designs nicht parallel auf mehreren Kernen ausgeführt werden können.Da die Speicherverwaltung in Python nicht threadsicher ist, erfordert jeder Thread einen exklusiven Zugriff auf Datenstrukturen im Python-Interpreter. Dieser exklusive Zugriff wird durch einen Mechanismus namens (Global Interpretr Lock) erworben .
GIL
Why does python use GIL?
Um zu verhindern, dass mehrere Threads gleichzeitig auf den Interpreter-Status zugreifen und den Interpreter-Status beschädigen.
Die Idee ist, wann immer ein Thread ausgeführt wird (auch wenn es der Hauptthread ist) , eine GIL erfasst wird und nach einem vordefinierten Zeitintervall die GIL vom aktuellen Thread freigegeben und von einem anderen Thread (falls vorhanden) erneut erfasst wird.
Why not simply remove GIL?
Es ist nicht so, dass es unmöglich ist, GIL zu entfernen, es ist nur so, dass wir in diesem Fall mehrere Sperren in den Interpreter einfügen, um den Zugriff zu serialisieren, was selbst eine einzelne Thread-Anwendung weniger leistungsfähig macht.
Daher werden die Kosten für das Entfernen von GIL durch eine verringerte Leistung einer einzelnen Thread-Anwendung bezahlt, was niemals erwünscht ist.
So when does thread switching occurs in python?
Der Thread-Wechsel erfolgt, wenn GIL freigegeben wird. Wann wird GIL freigegeben? Es sind zwei Szenarien zu berücksichtigen.
Wenn ein Thread CPU-gebundene Operationen ausführt (Ex-Bildverarbeitung).
In älteren Python-Versionen wurde die Thread-Umschaltung nach einer festgelegten Anzahl von Python-Anweisungen durchgeführt. Standardmäßig wurde diese
100
Option festgelegt. Es stellte sich heraus, dass es keine sehr gute Richtlinie ist, zu entscheiden, wann die Umschaltung erfolgen soll, da für die Ausführung einer einzelnen Anweisung Zeit aufgewendet wurde kann sehr wild von Millisekunde bis zu einer Sekunde sein. Daher ist die Freigabe von GIL nach jeder100
Anweisung unabhängig von der Zeit, die sie für die Ausführung benötigen, eine schlechte Richtlinie.In neuen Versionen wird anstelle der Befehlsanzahl als Metrik zum Wechseln des Threads ein konfigurierbares Zeitintervall verwendet. Das Standardschaltintervall beträgt 5 Millisekunden. Sie können das aktuelle Schaltintervall mit abrufen
sys.getswitchinterval()
. Dies kann mit geändert werdensys.setswitchinterval()
Wenn ein Thread einige E / A-gebundene Operationen ausführt (Ex-Dateisystemzugriff oder
Netzwerk-E / A)
GIL wird freigegeben, wenn der Thread darauf wartet, dass der E / A-Vorgang abgeschlossen ist.
Which thread to switch to next?
Der Interpreter hat keinen eigenen Scheduler. Welcher Thread am Ende des Intervalls geplant wird, ist die Entscheidung des Betriebssystems. .
quelle
Eine einfache Lösung für die GIL ist das Multiprozessor- Modul. Es kann als Ersatz für das Threading-Modul verwendet werden, verwendet jedoch mehrere Interpreter-Prozesse anstelle von Threads. Aus diesem Grund ist der Aufwand für einfache Dinge etwas höher als für einfaches Threading, bietet Ihnen jedoch den Vorteil einer echten Parallelisierung, wenn Sie diese benötigen. Es lässt sich auch problemlos auf mehrere physische Maschinen skalieren.
Wenn Sie eine wirklich groß angelegte Parallelisierung benötigen, würde ich weiter schauen, aber wenn Sie nur auf alle Kerne eines Computers oder auf einige andere skalieren möchten, ohne all die Arbeit, die für die Implementierung eines umfassenderen Frameworks erforderlich wäre, dann ist dies für Sie .
quelle
Denken Sie daran, dass die GIL von Zeit zu Zeit abgefragt wird, um das Erscheinungsbild mehrerer Aufgaben anzuzeigen. Diese Einstellung kann fein abgestimmt werden, aber ich biete den Vorschlag an, dass die Threads arbeiten sollten oder dass viele Kontextwechsel Probleme verursachen werden.
Ich würde so weit gehen, mehrere Eltern auf Prozessoren vorzuschlagen und zu versuchen, ähnliche Jobs auf demselben Kern zu behalten.
quelle