Wie werden in Python speziell Variablen zwischen Threads geteilt?
Obwohl ich zuvor verwendet habe, habe threading.Thread
ich nie wirklich verstanden oder Beispiele dafür gesehen, wie Variablen geteilt wurden. Werden sie zwischen dem Hauptthema und den Kindern oder nur unter den Kindern geteilt? Wann müsste ich lokalen Thread-Speicher verwenden, um diese Freigabe zu vermeiden?
Ich habe viele Warnungen bezüglich der Synchronisierung des Zugriffs auf gemeinsam genutzte Daten zwischen Threads mithilfe von Sperren gesehen, aber ich habe noch kein wirklich gutes Beispiel für das Problem gefunden.
Danke im Voraus!
Antworten:
In Python wird alles gemeinsam genutzt, mit Ausnahme der funktionslokalen Variablen (da jeder Funktionsaufruf seine eigenen lokalen Elemente erhält und Threads immer separate Funktionsaufrufe sind.) Und selbst dann nur die Variablen selbst (die Namen, die sich auf Objekte beziehen). sind lokal für die Funktion; Objekte selbst sind immer global und alles kann auf sie verweisen. Das
Thread
Objekt für einen bestimmten Thread ist in dieser Hinsicht kein spezielles Objekt. Wenn Sie dasThread
Objekt an einem Ort speichern, auf den alle Threads zugreifen können (wie bei einer globalen Variablen), können alle Threads auf dieses eineThread
Objekt zugreifen . Wenn Sie etwas atomar ändern möchten, auf das ein anderer Thread Zugriff hat, müssen Sie ihn mit einer Sperre schützen. Und alle Threads müssen natürlich dieselbe Sperre haben, sonst wäre es nicht sehr effektiv.Wenn Sie einen tatsächlichen threadlokalen Speicher möchten,
threading.local
kommt dies ins Spiel. Attribute vonthreading.local
werden nicht zwischen Threads geteilt. Jeder Thread sieht nur die Attribute, die er selbst dort platziert hat. Wenn Sie neugierig auf die Implementierung sind, befindet sich die Quelle in der Standardbibliothek in _threading_local.py .quelle
Betrachten Sie den folgenden Code:
Hier wird threading.local () als schnelle und schmutzige Methode verwendet, um einige Daten von run () an bar () zu übergeben, ohne die Schnittstelle von foo () zu ändern.
Beachten Sie, dass die Verwendung globaler Variablen nicht ausreicht:
Wenn Sie es sich leisten könnten, diese Daten als Argument von foo () weiterzugeben, wäre dies eine elegantere und besser gestaltete Methode:
Dies ist jedoch nicht immer möglich, wenn Sie Code von Drittanbietern oder schlecht gestalteten verwenden.
quelle
Sie können einen lokalen Thread-Speicher mit erstellen
threading.local()
.In den TLS gespeicherte Daten sind für jeden Thread eindeutig, wodurch sichergestellt wird, dass keine unbeabsichtigte Freigabe erfolgt.
quelle
Wie in jeder anderen Sprache hat jeder Thread in Python Zugriff auf dieselben Variablen. Es gibt keinen Unterschied zwischen dem Hauptthread und den untergeordneten Threads.
Ein Unterschied zu Python besteht darin, dass die globale Interpreter-Sperre bedeutet, dass jeweils nur ein Thread Python-Code ausführen kann. Dies ist jedoch keine große Hilfe, wenn es um die Synchronisierung des Zugriffs geht, da immer noch alle üblichen Vorkaufsprobleme auftreten und Sie Threading-Grundelemente wie in anderen Sprachen verwenden müssen. Es bedeutet jedoch, dass Sie erneut überlegen müssen, ob Sie Threads für die Leistung verwendet haben.
quelle
Ich kann mich hier irren. Wenn Sie etwas anderes wissen, erläutern Sie dies bitte, da dies erklären würde, warum Thread local () verwendet werden muss.
Diese Aussage scheint nicht falsch zu sein: "Wenn Sie etwas atomar ändern möchten, auf das ein anderer Thread Zugriff hat, müssen Sie es mit einer Sperre schützen." Ich denke, diese Aussage ist -> effektiv <- richtig, aber nicht ganz richtig. Ich dachte, der Begriff "atomar" bedeutete, dass der Python-Interpreter einen Bytecode-Block erstellte, der keinen Platz für ein Interrupt-Signal an die CPU ließ.
Ich dachte, atomare Operationen sind Teile des Python-Bytecodes, die keinen Zugriff auf Interrupts gewähren. Python-Anweisungen wie "running = True" sind atomar. In diesem Fall müssen Sie die CPU nicht vor Interrupts sperren (glaube ich). Die Aufschlüsselung des Python-Bytecodes ist vor Thread-Unterbrechungen geschützt.
Python-Code wie "threads_running [5] = True" ist nicht atomar. Hier gibt es zwei Teile des Python-Bytecodes. eine, um die Liste () für ein Objekt zu de-referenzieren, und eine andere Bytecode-Block, um einem Objekt einen Wert zuzuweisen, in diesem Fall eine "Stelle" in einer Liste. Ein Interrupt kann ausgelöst werden -> zwischen <- den beiden Byte-Code -> Chunks <-. Dort passieren schlimme Dinge.
In welcher Beziehung steht thread local () zu "atomar"? Deshalb scheint mir die Aussage falsch zu sein. Wenn nicht, können Sie das erklären?
quelle