Inter-Thread Communicatie in Python Beheersen: Synchronisatie & Data Delen
Inter-Thread Communicatie verwijst naar het proces van het mogelijk maken van communicatie en synchronisatie tussen threads binnen een Python multi-threaded programma.
Over het algemeen delen threads in Python hetzelfde geheugenruimte binnen een proces, wat hen in staat stelt om data uit te wisselen en hun activiteiten te coördineren via gedeelde variabelen, objecten en gespecialiseerde synchronisatiemechanismen die door de threading module worden geleverd.
Om inter-thread communicatie te faciliteren, biedt de threading module diverse synchronisatieprimitieven zoals Locks, Events, Conditions en Semaphores objecten. In deze tutorial leert u hoe u de Event en Condition objecten gebruikt voor communicatie tussen threads in een multi-threaded programma.
Het Event Object
Een Event object beheert de staat van een interne vlag zodat threads kunnen wachten of instellen. Het Event object biedt methoden om de staat van deze vlag te controleren, zodat threads hun activiteiten kunnen synchroniseren op basis van gedeelde condities.
De vlag is initieel false en wordt true met de set() methode en terug gezet naar false met de clear() methode. De wait() methode blokkeert tot de vlag true is.
Hieronder volgen de belangrijkste methoden van het Event object:
- is_set(): Retourneert True als en slechts als de interne vlag true is.
- set(): Zet de interne vlag op true. Alle threads die wachten tot het true wordt, worden gewekt. Threads die wait() aanroepen zodra de vlag true is, zullen helemaal niet blokkeren.
- clear(): Reset de interne vlag naar false. Vervolgens zullen threads die wait() aanroepen blokkeren tot set() wordt aangeroepen om de interne vlag weer op true te zetten.
- wait(timeout=None): Blokkeert tot de interne vlag true is. Als de interne vlag true is bij invoer, retourneert het onmiddellijk. Anders blokkeert het tot een andere thread set() aanroept om de vlag op true te zetten, of tot de optionele timeout optreedt. Wanneer het timeout-argument aanwezig is en niet None is, moet het een drijvende-komma getal zijn dat een timeout voor de operatie in seconden specificeert.
Voorbeeld
De volgende code probeert de verkeersstroom te simuleren die wordt geregeld door de toestand van het verkeerslicht, ofwel GROEN of ROOD.
Er zijn twee threads in het programma, gericht op twee verschillende functies. De signal_state() functie stelt en reset de event periodiek, wat een verandering van signaal van GROEN naar ROOD aangeeft.
De traffic_flow() functie wacht tot de event wordt ingesteld, en draait een lus zolang het ingesteld blijft.
from threading import Event, Thread
import time
terminate = False
def signal_state():
global terminate
while not terminate:
time.sleep(0.5)
print("Verkeersagent Geeft GROEN Signaal")
event.set()
time.sleep(1)
print("Verkeersagent Geeft ROOD Signaal")
event.clear()
def traffic_flow():
global terminate
num = 0
while num < 10 and not terminate:
print("Wachten op GROEN Signaal")
event.wait()
print("GROEN Signaal ... Verkeer Kan Rijden")
while event.is_set() and not terminate:
num += 1
print("Voertuig Nr:", num, " Kruist het Signaal")
time.sleep(1)
print("ROOD Signaal ... Verkeer Moet Wachten")
event = Event()
t1 = Thread(target=signal_state)
t2 = Thread(target=traffic_flow)
t1.start()
t2.start()
# Beëindig threads na enige tijd
time.sleep(5)
terminate = True
# join alle threads om te voltooien
t1.join()
t2.join()
print("Hoofdthread Afsluiten")
Uitvoer
Bij uitvoering van de bovenstaande code krijgt u de volgende uitvoer:
Wachten op GROEN Signaal Verkeersagent Geeft GROEN Signaal GROEN Signaal ... Verkeer Kan Rijden Voertuig Nr: 1 Kruist het Signaal Verkeersagent Geeft ROOD Signaal ROOD Signaal ... Verkeer Moet Wachten Wachten op GROEN Signaal Verkeersagent Geeft GROEN Signaal GROEN Signaal ... Verkeer Kan Rijden Voertuig Nr: 2 Kruist het Signaal Voertuig Nr: 3 Kruist het Signaal Verkeersagent Geeft ROOD Signaal Verkeersagent Geeft GROEN Signaal Voertuig Nr: 4 Kruist het Signaal Verkeersagent Geeft ROOD Signaal ROOD Signaal ... Verkeer Moet Wachten Verkeersagent Geeft GROEN Signaal Verkeersagent Geeft ROOD Signaal Hoofdthread Afsluiten
Het Condition Object
Het Condition object in Python's threading module biedt een geavanceerdere synchronisatiemechanisme. Het stelt threads in staat om te wachten op een notificatie van een andere thread voordat ze doorgaan. Condition objecten zijn altijd geassocieerd met een lock en bieden mechanismen voor signalering tussen threads.
Hieronder volgt de syntaxis van de threading.Condition() klasse:
threading.Condition(lock=None)
Hieronder staan de belangrijkste methoden van het Condition object:
- acquire(*args): Verkrijgt de onderliggende lock. Deze methode roept de corresponderende methode op de onderliggende lock aan; de retourwaarde is wat die methode retourneert.
- release(): Geeft de onderliggende lock vrij. Deze methode roept de corresponderende methode op de onderliggende lock aan; er is geen retourwaarde.
- wait(timeout=None): Deze methode geeft de onderliggende lock vrij, en blokkeert vervolgens tot het wordt gewekt door een notify() of notify_all() aanroep voor dezelfde condition variable in een andere thread, of tot de optionele timeout optreedt. Eenmaal gewekt of timeout, verkrijgt het de lock opnieuw en retourneert.
- wait_for(predicate, timeout=None): Deze hulpmethode kan wait() herhaaldelijk aanroepen tot het predicate vervuld is, of tot een timeout optreedt. De retourwaarde is de laatste retourwaarde van het predicate en zal evalueren naar False als de methode timeout heeft.
- notify(n=1): Deze methode wekt ten hoogste n van de threads die wachten op de condition variable; het is een no-op als er geen threads wachten.
- notify_all(): Wekt alle threads die wachten op deze condition. Deze methode werkt als notify(), maar wekt alle wachtende threads in plaats van één. Als de aanroepende thread de lock niet heeft verworven wanneer deze methode wordt aangeroepen, wordt een RuntimeError gegooid.
Voorbeeld
Dit voorbeeld demonstreert een eenvoudige vorm van inter-thread communicatie met het Condition object van Python's threading module. Hier communiceren thread_a en thread_b met een Condition object, thread_a wacht tot het een notificatie ontvangt van thread_b. thread_b slaapt 2 seconden voordat het thread_a notificeert en dan afloopt.
from threading import Condition, Thread
import time
c = Condition()
def thread_a():
print("Thread A gestart")
with c:
print("Thread A wacht op toestemming...")
c.wait()
print("Thread A kreeg toestemming!")
print("Thread A afgerond")
def thread_b():
print("Thread B gestart")
with c:
time.sleep(2)
print("Thread A Notificeren...")
c.notify()
print("Thread B afgerond")
Thread(target=thread_a).start()
Thread(target=thread_b).start()
Uitvoer
Bij uitvoering van de bovenstaande code krijgt u de volgende uitvoer:
Thread A gestart Thread A wacht op toestemming... Thread B gestart Thread A Notificeren... Thread B afgerond Thread A kreeg toestemming! Thread A afgerond
Voorbeeld
Hier is een andere code die demonstreert hoe het Condition object gebruikt wordt voor communicatie tussen threads. In dit voorbeeld draait thread t2 de taskB() functie, en thread t1 draait de taskA() functie. De t1 thread verkrijgt de condition en notificeert het.
Op dat moment is de t2 thread in een wachttoestand. Nadat de condition wordt vrijgegeven, gaat de wachtende thread door om het willekeurige getal te consumeren gegenereerd door de notifierende functie.
from threading import Condition, Thread
import time
import random
numbers = []
def taskA(c):
for _ in range(5):
with c:
num = random.randint(1, 10)
print("Gegenereerd willekeurig getal:", num)
numbers.append(num)
print("Notificatie uitgegeven")
c.notify()
time.sleep(0.3)
def taskB(c):
for i in range(5):
with c:
print("Wachten op update")
while not numbers:
c.wait()
print("Ontvangen willekeurig getal", numbers.pop())
time.sleep(0.3)
c = Condition()
t1 = Thread(target=taskB, args=(c,))
t2 = Thread(target=taskA, args=(c,))
t1.start()
t2.start()
t1.join()
t2.join()
print("Klaar")
Wanneer u deze code uitvoert, produceert het de volgende uitvoer:
Wachten op update Gegenereerd willekeurig getal: 2 Notificatie uitgegeven Ontvangen willekeurig getal 2 Gegenereerd willekeurig getal: 5 Notificatie uitgegeven Wachten op update Ontvangen willekeurig getal 5 Gegenereerd willekeurig getal: 1 Notificatie uitgegeven Wachten op update Ontvangen willekeurig getal 1 Gegenereerd willekeurig getal: 9 Notificatie uitgegeven Wachten op update Ontvangen willekeurig getal 9 Gegenereerd willekeurig getal: 2 Notificatie uitgegeven Wachten op update Ontvangen willekeurig getal 2 Klaar
Python
- Een minimale Python-versie afdwingen in je script
- Meerdere waarden retourneren in Python: een eenvoudige gids
- Python DSL's: Op Maat Gemaakte Oplossingen voor Gespecialiseerde Domeinen
- Python Statements, Indentatie en Comments: Een duidelijke gids
- Python-decorators beheersen: functies verbeteren met expert-technieken
- Flask vs Django: Belangrijkste Verschillen, Kenmerken en Het Juiste Framework Kiezen
- Python Geheugenlekken Oplossen: Diagnosticeren & Performanceproblemen Verhelpen
- De Real Python Podcast – Wekelijkse Inzichten, Interviews & Coder Tips
- Python abs()-functie: absolute waarden berekenen voor getallen & complexe getallen
- 5 experttechnieken om strings in Python om te keren
- Python print()-functie: Praktische handleiding met voorbeelden