Heim >Backend-Entwicklung >Python-Tutorial >Python-Thread-Praktiken
"""" Es gibt zwei Möglichkeiten, Threads in Python zu verwenden: Funktionen oder Klassen zum Umschließen von Thread-Objekten.
1. Funktional: Rufen Sie die Funktion start_new_thread() im Thread-Modul auf, um einen neuen Thread zu generieren. Der Thread kann beendet werden, indem man darauf wartet, dass der Thread auf natürliche Weise endet, oder indem man die Methode thread.exit() oder thread.exit_thread() in der Thread-Funktion aufruft.
import time
import thread
def timer(no,interval):
cnt=0
while cnt<10:
print 'thread(%d )'%(cnt)
time.sleep(interval)
cnt=cnt+1
def test():
thread.start_new_thread(timer,(1,1 ))
thread.start_new_thread(timer,(2,2))
if __name__=='__main__':
print 'thread Starting'
test()
time. sleep(20)
thread.exit_thread()
print 'exit...'
2. Erstellen Sie eine Unterklasse von threading.Thread, um ein Thread-Objekt zu umschließen,
Verwendung der threading.Thread-Klasse:
1, rufen Sie threading.Thread.__init__(self, name = threadname) im __init__ Ihrer eigenen Thread-Klasse auf
Threadname ist der Name des Threads
2, run() muss normalerweise neu geschrieben und geschrieben werden, um die erforderlichen Funktionen zu erreichen.
3. getName(), Thread-Objektnamen abrufen
4. setName(), Thread-Objektnamen festlegen
5 🎜>
6, jion([timeout]), warten Sie, bis ein weiterer Thread endet, bevor Sie ihn ausführen.
7, setDaemon(bool), legt fest, ob der Sub-Thread mit dem Haupt-Thread endet und muss vor start() aufgerufen werden. Der Standardwert ist False.
8, isDaemon(), bestimmt, ob der Thread mit dem Hauptthread endet.
9, isAlive(), prüfen Sie, ob der Thread ausgeführt wird.
Threading importieren
Zeit importieren
Klassentimer(threading.Thread):
def __init__(self,num,interval):
threading.Thread.__init__(self)
self.thread_num=num
self.interval=interval
self.thread_stop=False
def run(self):
while not self.thread_stop:
print 'thread object (%d), Zeit %sn' %(self.thread_num,time.ctime())
time.sleep(self.interval)
def stop(self):
self.thread_stop =True
def test():
thread1=timer(1,1)
thread2=timer(2,2)
thread1.start()
thread2.start( )
time.sleep(10)
thread1.stop()
thread2.stop()
return
if __name__=='__main__':
test()
"""
"""
Der Grund für das Problem liegt darin, dass der Zugriff mehrerer Threads auf dieselbe Ressource nicht kontrolliert wird, was zu Datenschäden führt und die Ergebnisse des Thread-Betriebs unvorhersehbar macht. Dieses Phänomen wird als „Thread-unsicher“ bezeichnet.
Threading importieren
Zeit importieren
class MyThread(threading.Thread):
def run(self):
for i in range(3):
time.sleep (1)
msg='I am '+ self.getName()+'@'+str(i)
print msg
def test():
for i in range (5):
t=MyThread()
t.start()
if __name__=='__main__':
test()
Das obige Beispiel führt zu Das häufigste Problem der Multithread-Programmierung: Datenaustausch. Wenn mehrere Threads bestimmte gemeinsam genutzte Daten ändern, ist eine Synchronisationssteuerung erforderlich.
Thread-Synchronisierung kann sicherstellen, dass mehrere Threads sicher auf konkurrierende Ressourcen zugreifen. Der einfachste Synchronisierungsmechanismus besteht darin, eine Mutex-Sperre einzuführen. Ein Mutex führt einen Zustand für eine Ressource ein: gesperrt/entsperrt. Wenn ein Thread gemeinsam genutzte Daten ändern möchte, muss er diese zunächst sperren. Zu diesem Zeitpunkt ist der Status der Ressource „gesperrt“ und andere Threads können ihn nicht ändern, bis der Thread die Ressource freigibt und den Status der Ressource in „sperrt“. entsperrt“, andere Threads können die Ressource wieder sperren. Die Mutex-Sperre stellt sicher, dass jeweils nur ein Thread Schreibvorgänge ausführt und stellt so die Korrektheit der Daten in Multithread-Situationen sicher. Unter anderem kann die Sperrmethode „Akquisition“ einen optionalen Parameter „Timeout“ für den Timeout-Zeitraum haben. Wenn eine Zeitüberschreitung festgelegt ist, kann der Rückgabewert verwendet werden, um festzustellen, ob die Sperre nach der Zeitüberschreitung erhalten wurde, sodass eine andere Verarbeitung durchgeführt werden kann
Die Lock-Klasse ist im Threading-Modul
import definiert Threading
Importzeit
class MyThread(threading.Thread):
def run(self):
globale Nummer
time.sleep(1)
if mutex.acquire():
num=num+1
print self.name+' set num to '+str(num)+ 'n'
mutex.release()
num=0
mutex=threading.Lock()
def test():
for i in range(5):
t=MyThread()
t.start()
if __name__=='__main__':
test()
"""
"""Einfacher Ein Deadlock Die Situation liegt vor, wenn ein Thread „iteriert“, um dieselbe Ressource anzufordern, was direkt zu einem Deadlock führt:
Import Threading
Import Time
class MyThread(threading.Thread):
def run (self):
global num
time.sleep(1)
if mutex.acquire(1):
num = num+1
msg = self .name+' set num to '+str(num)
print msg
mutex.acquire()
mutex.release()
mutex.release()
num = 0
mutex = threading. Lock()
def test():
for i in range(5):
t = MyThread()
t.start()
if __name__ == '__main__':
test()
Um mehrere Anforderungen für dieselbe Ressource im selben Thread zu unterstützen, stellt Python eine „Wiedereintrittssperre“ bereit: threading.RLock. RLock verwaltet intern eine Sperre und eine Zählervariable. Der Zähler zeichnet die Anzahl der Erfassungen auf, sodass die Ressource mehrmals benötigt werden kann. Bis alle Acquires eines Threads freigegeben sind, können andere Threads Ressourcen abrufen. Wenn im obigen Beispiel RLock anstelle von Lock verwendet wird, tritt kein Deadlock auf:
import threading
import time
class MyThread(threading.Thread):
def run(self) :
globale Nummer
time.sleep(1)
if mutex.acquire(1):
num = num+1
set msg = self.name+' num auf ' +str (num)
print msg
num mutex.acquire()
mutex.release() mutex.release()
num = 0
mutex = threading()
def test():
for i in range(5):
t = MyThread()
t.start()
if __name__ == '__main__':
test()
"""
"""
Python-Multithread-Programmierung (5): Synchronisierung von Bedingungsvariablen
Mutex-Sperre ist der einfachste Thread-Synchronisationsmechanismus. Bedingung wird von Python-Objekten bereitgestellt bieten Unterstützung für komplexe Thread-Synchronisierungsprobleme. Bedingung wird als Bedingungsvariable bezeichnet. Zusätzlich zur Bereitstellung von Erfassungs- und Freigabemethoden wie Lock bietet sie auch Warte- und Benachrichtigungsmethoden. Der Thread erfasst zunächst eine Bedingungsvariable und bestimmt dann einige Bedingungen. Wenn die Bedingung nicht erfüllt ist, führen Sie eine Verarbeitung durch, um die Bedingung zu ändern, und benachrichtigen Sie andere Threads über die Benachrichtigungsmethode. Andere Threads im Wartezustand beurteilen die Bedingung erneut, nachdem sie die Benachrichtigung erhalten haben. Dieser Vorgang wird kontinuierlich wiederholt, um komplexe Synchronisationsprobleme zu lösen.
Man kann davon ausgehen, dass das Condition-Objekt eine Sperre (Lock/RLock) und einen Wartepool verwaltet. Der Thread erhält das Condition-Objekt durch Acquire. Wenn die Wartemethode aufgerufen wird, gibt der Thread die Sperre innerhalb der Bedingung auf und wechselt in den blockierten Zustand. Gleichzeitig wird der Thread im Wartepool aufgezeichnet. Wenn die Notify-Methode aufgerufen wird, wählt das Condition-Objekt einen Thread aus dem Wartepool aus und weist ihn an, die Acquire-Methode aufzurufen, um zu versuchen, die Sperre zu erhalten.
Der Konstruktor des Condition-Objekts kann ein Lock/RLock-Objekt als Parameter akzeptieren. Wenn nicht angegeben, erstellt das Condition-Objekt intern ein RLock.
Zusätzlich zur Notify-Methode stellt das Condition-Objekt auch die NotifyAll-Methode bereit, die alle Threads im Wartepool benachrichtigen kann, um zu versuchen, die interne Sperre zu erhalten. Aufgrund des oben genannten Mechanismus können Threads im Wartezustand nur über die Benachrichtigungsmethode aktiviert werden. Die Funktion von notifyAll besteht also darin, zu verhindern, dass Threads für immer still bleiben.
Das klassische Problem, das die Synchronisierung von Bedingungsvariablen demonstriert, ist das Produzenten- und Konsumentenproblem: Angenommen, es gibt eine Gruppe von Produzenten (Produzent) und eine Gruppe von Konsumenten (Konsumer), die über einen Markt mit Produkten interagieren. Die „Strategie“ des Herstellers besteht darin, 100 Produkte zu produzieren und auf den Markt zu bringen, wenn weniger als 1.000 Produkte auf dem Markt sind, während die „Strategie“ des Verbrauchers darin besteht, 100 Produkte zu produzieren, wenn mehr als 100 Produkte auf dem Markt sind . Verbrauchen Sie 3 Produkte. Der Code zur Verwendung von Condition zur Lösung des Produzenten- und Konsumentenproblems lautet wie folgt:
Import Threading
Import Time
class Producer(threading.Thread):
def run(self):
global count
while True:
if con.acquire():
if count>1000:
con.wait()
else:
count=count+100
print self.name+' Produce 100,count='+str(count)
con.release()
time.sleep(1)
class Customer(threading. Thread):
def run(self):
global count
while True:
if con.acquire():
if count>100:
count=count-100
print self .name+ 'consume 100, count='+str(count)
else:
con.wait()
con.release()
time.sleep(1)
count=500
con=threading.Condition()
def test():
for i in range(5):
p=Producer()
p.start( )
c=Customer()
c.start()
print i
if __name__=='__main__':
test()
Python Standardmäßig können globale Variablen in der Funktion gelesen, aber nicht geschrieben werden.
ist jedoch nur für con lesbar, daher besteht keine Notwendigkeit, globale Variablen einzuführen