it-swarm.com.de

Was ist "Thread Local Storage" in Python und warum brauche ich es?

Wie werden in Python spezifisch Variablen zwischen Threads geteilt?

Obwohl ich threading.Thread Verwendet habe, habe ich nie wirklich verstanden oder Beispiele dafür gesehen, wie Variablen geteilt wurden. Werden sie zwischen dem Hauptthema und den Kindern geteilt oder nur zwischen den Kindern? Wann muss ich Thread-lokalen Speicher verwenden, um diese Freigabe zu vermeiden?

Ich habe viele Warnungen zum Synchronisieren des Zugriffs auf freigegebene Daten zwischen Threads mithilfe von Sperren gesehen, aber ich habe noch kein wirklich gutes Beispiel für das Problem gefunden.

Danke im Voraus!

87
Mike

In Python wird bis auf funktionslokale Variablen alles gemeinsam genutzt (da jeder Funktionsaufruf einen eigenen Satz von lokalen Variablen erhält und Threads immer separate Funktionsaufrufe sind.) Und selbst dann nur die Variablen selbst (die Namen, die auf Objekte verweisen) sind lokal für die Funktion; Objekte selbst sind immer global und alles kann auf sie verweisen. Das Objekt Thread für einen bestimmten Thread ist in dieser Hinsicht kein spezielles Objekt. Wenn Sie das Objekt Thread an einer Stelle speichern, auf die alle Threads zugreifen können (wie eine globale Variable), können alle Threads auf dieses eine Objekt Thread zugreifen. Wenn Sie irgendetwas atomar modifizieren möchten , das Sie nicht gerade in demselben Thread erstellt und nirgendwo gespeichert haben, wo ein anderer Thread darauf zugreifen kann, Sie müssen es durch ein Schloss schützen. Und natürlich müssen alle Threads dieselbe Sperre haben, sonst wäre dies nicht sehr effektiv.

Wenn Sie tatsächlichen Thread-lokalen Speicher möchten, ist das, wo threading.local kommt herein. Attribute von threading.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, finden Sie die Quelle in _ threading_local.py in der Standardbibliothek.

74
Thomas Wouters

Betrachten Sie den folgenden Code:

#/usr/bin/env python

from time import sleep
from random import random
from threading import Thread, local

data = local()

def bar():
    print("I'm called from", data.v)

def foo():
    bar()

class T(Thread):
    def run(self):
        sleep(random())
        data.v = self.getName()   # Thread-1 and Thread-2 accordingly
        sleep(1)
        foo()
 >> T (). Start (); T (). Start () 
 Ich werde von Thread-2 angerufen 
 Ich werde von Thread-1 angerufen 

Hier wird threading.local () als schnelle und fehlerhafte 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:

#/usr/bin/env python

from time import sleep
from random import random
from threading import Thread

def bar():
    global v
    print("I'm called from", v)

def foo():
    bar()

class T(Thread):
    def run(self):
        global v
        sleep(random())
        v = self.getName()   # Thread-1 and Thread-2 accordingly
        sleep(1)
        foo()
 >> T (). Start (); T (). Start () 
 Ich werde von Thread-2 angerufen 
 Ich werde von Thread-2 angerufen 

Wenn Sie es sich in der Zwischenzeit leisten könnten, diese Daten als Argument von foo () durchzuleiten, wäre dies eine elegantere und besser gestaltete Methode:

from threading import Thread

def bar(v):
    print("I'm called from", v)

def foo(v):
    bar(v)

class T(Thread):
    def run(self):
        foo(self.getName())

Dies ist jedoch nicht immer möglich, wenn Code von Drittanbietern oder schlecht entworfener Code verwendet wird.

65
ahatchkins

Sie können einen lokalen Thread-Speicher mit threading.local() erstellen.

>>> tls = threading.local()
>>> tls.x = 4 
>>> tls.x
4

In tls gespeicherte Daten sind für jeden Thread eindeutig, wodurch sichergestellt wird, dass keine unbeabsichtigte Weitergabe erfolgt.

17
Aaron Maenpaa

Wie in jeder anderen Sprache hat jeder Thread in Python) Zugriff auf dieselben Variablen. Es gibt keinen Unterschied zwischen dem 'Haupt-Thread' und dem untergeordneten Thread.

Ein Unterschied zu Python ist, dass die globale Interpretersperre bedeutet, dass immer nur ein Thread gleichzeitig ausgeführt werden kann Python Code. Dies ist keine große Hilfe Beim Synchronisieren des Zugriffs treten jedoch immer noch die üblichen Probleme mit der Voreinstellung auf, und Sie müssen Threading-Primitive wie in anderen Sprachen verwenden.

2
Nick Johnson