Beheersing van communicatie tussen threads in Python:synchronisatie en gegevensuitwisseling
Inter-Thread Communication 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 dezelfde geheugenruimte binnen een proces, waardoor ze gegevens kunnen uitwisselen en hun activiteiten kunnen coördineren via gedeelde variabelen, objecten en gespecialiseerde synchronisatiemechanismen die door de threading-module worden geleverd.
Om de communicatie tussen threads te vergemakkelijken, biedt de threadingmodule verschillende synchronisatieprimitieven zoals Locks, Events, Condities en Semaphores-objecten. In deze tutorial leert u hoe u het Event- en Condition-object kunt gebruiken voor het verzorgen van de communicatie tussen threads in een programma met meerdere threads.
Het gebeurtenisobject
Een Event-object beheert de status van een interne vlag, zodat threads kunnen wachten of worden ingesteld. Event-object biedt methoden om de status van deze vlag te controleren, waardoor threads hun activiteiten kunnen synchroniseren op basis van gedeelde voorwaarden.
De vlag is aanvankelijk false en wordt waar met de set()-methode en wordt opnieuw ingesteld op false met de clear()-methode. De wait() methode blokkeert totdat de vlag waar is.
Hieronder volgen de belangrijkste methoden van het Event-object −
- is_set():Retourneert True als en slechts als de interne vlag waar is.
- set():Stel de interne vlag in op true. Alle draden die wachten tot het waar wordt, worden gewekt. Threads die wait() aanroepen zodra de vlag waar is, worden helemaal niet geblokkeerd.
- clear():Reset de interne vlag naar false. Vervolgens zullen threads die wait() aanroepen, blokkeren totdat set() wordt aangeroepen om de interne vlag weer op true te zetten.
- wait(timeout=None):Blokkeren totdat de interne vlag waar is. Als de interne vlag bij binnenkomst waar is, keer dan onmiddellijk terug. Anders blokkeert u totdat een andere thread set() aanroept om de vlag op true in te stellen, of totdat de optionele time-out optreedt. Als het time-outargument aanwezig is en niet Geen, moet het een getal met drijvende komma zijn dat een time-out voor de bewerking in seconden specificeert.
Voorbeeld
De volgende code probeert de verkeersstroom te simuleren die wordt geregeld door de status van het verkeerssignaal GROEN of ROOD.
Er zijn twee threads in het programma, gericht op twee verschillende functies. De functie signal_state() stelt periodiek de gebeurtenis in en reset deze die de verandering van het signaal van GROEN naar ROOD aangeeft.
De functie traffic_flow() wacht tot de gebeurtenis is ingesteld en voert een lus uit totdat deze ingesteld blijft.
from threading import Event, Thread
import time
terminate = False
def signal_state():
global terminate
while not terminate:
time.sleep(0.5)
print("Traffic Police Giving GREEN Signal")
event.set()
time.sleep(1)
print("Traffic Police Giving RED Signal")
event.clear()
def traffic_flow():
global terminate
num = 0
while num < 10 and not terminate:
print("Waiting for GREEN Signal")
event.wait()
print("GREEN Signal ... Traffic can move")
while event.is_set() and not terminate:
num += 1
print("Vehicle No:", num," Crossing the Signal")
time.sleep(1)
print("RED Signal ... Traffic has to wait")
event = Event()
t1 = Thread(target=signal_state)
t2 = Thread(target=traffic_flow)
t1.start()
t2.start()
# Terminate the threads after some time
time.sleep(5)
terminate = True
# join all threads to complete
t1.join()
t2.join()
print("Exiting Main Thread")
Uitvoer
Bij het uitvoeren van de bovenstaande code krijgt u de volgende uitvoer −
Waiting for GREEN Signal Traffic Police Giving GREEN Signal GREEN Signal ... Traffic can move Vehicle No: 1 Crossing the Signal Traffic Police Giving RED Signal RED Signal ... Traffic has to wait Waiting for GREEN Signal Traffic Police Giving GREEN Signal GREEN Signal ... Traffic can move Vehicle No: 2 Crossing the Signal Vehicle No: 3 Crossing the Signal Traffic Police Giving RED Signal Traffic Police Giving GREEN Signal Vehicle No: 4 Crossing the Signal Traffic Police Giving RED Signal RED Signal ... Traffic has to wait Traffic Police Giving GREEN Signal Traffic Police Giving RED Signal Exiting Main Thread
Het voorwaardeobject
Het Condition-object in de threading-module van Python biedt een geavanceerder synchronisatiemechanisme. Hiermee kunnen threads wachten op een melding van een andere thread voordat ze verder gaan. Het Condition-object is altijd gekoppeld aan een vergrendeling en biedt mechanismen voor signalering tussen threads.
Hieronder volgt de syntaxis van de klasse threading.Condition() −
threading.Condition(lock=None)
Hieronder staan de belangrijkste methoden van het Condition-object −
- acquire(*args):Verkrijg het onderliggende slot. Deze methode roept de overeenkomstige methode op het onderliggende slot aan; de geretourneerde waarde is wat de methode retourneert.
- release():Ontgrendel het onderliggende slot. Deze methode roept de overeenkomstige methode op het onderliggende slot aan; er is geen retourwaarde.
- wait(timeout=None):Deze methode geeft de onderliggende vergrendeling vrij en blokkeert vervolgens totdat deze wordt geactiveerd door een notificatie() of notificatie_all() aanroep voor dezelfde voorwaardevariabele in een andere thread, of totdat de optionele time-out optreedt. Eenmaal ontwaakt of een time-out heeft bereikt, verkrijgt het de vergrendeling opnieuw en keert terug.
- wait_for(predikaat, timeout=None):Deze hulpprogrammamethode kan wait() herhaaldelijk aanroepen totdat aan het predikaat is voldaan, of totdat er een time-out optreedt. De geretourneerde waarde is de laatste geretourneerde waarde van het predikaat en wordt geëvalueerd als False als er een time-out is opgetreden bij de methode.
- notify(n=1):Deze methode activeert maximaal n van de threads die wachten op de condition-variabele; het is een no-op als er geen threads wachten.
- notify_all():Maak alle threads wakker die op deze voorwaarde wachten. Deze methode werkt als notificatie(), maar wekt alle wachtende threads op in plaats van één. Als de aanroepende thread de vergrendeling niet heeft verkregen wanneer deze methode wordt aangeroepen, wordt er een RuntimeError gegenereerd.
Voorbeeld
Dit voorbeeld demonstreert een eenvoudige vorm van communicatie tussen threads met behulp van het Condition-object van de threading-module van Python. Hier worden thread_a en thread_b gecommuniceerd met behulp van een Condition-object, de thread_a wacht totdat deze een melding ontvangt van thread_b. de thread_b slaapt 2 seconden voordat hij thread_a op de hoogte stelt en is dan klaar.
from threading import Condition, Thread
import time
c = Condition()
def thread_a():
print("Thread A started")
with c:
print("Thread A waiting for permission...")
c.wait()
print("Thread A got permission!")
print("Thread A finished")
def thread_b():
print("Thread B started")
with c:
time.sleep(2)
print("Notifying Thread A...")
c.notify()
print("Thread B finished")
Thread(target=thread_a).start()
Thread(target=thread_b).start()
Uitvoer
Bij het uitvoeren van de bovenstaande code krijgt u de volgende uitvoer −
Thread A started Thread A waiting for permission... Thread B started Notifying Thread A... Thread B finished Thread A got permission! Thread A finished
Voorbeeld
Hier is nog een code die demonstreert hoe het Condition-object wordt gebruikt voor het verzorgen van de communicatie tussen threads. Hierin voert de thread t2 de functie taskB() uit, en voert de thread t1 de functie taskA() uit. De t1-thread verkrijgt de voorwaarde en meldt deze.
Tegen die tijd bevindt de t2-thread zich in een wachtstatus. Nadat de voorwaarde is vrijgegeven, gaat de wachtende thread verder met het verbruiken van het willekeurige getal dat is gegenereerd door de meldingsfunctie.
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("Generated random number:", num)
numbers.append(num)
print("Notification issued")
c.notify()
time.sleep(0.3)
def taskB(c):
for i in range(5):
with c:
print("waiting for update")
while not numbers:
c.wait()
print("Obtained random number", 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("Done")
Wanneer u deze code uitvoert, zal deze de volgende uitvoer produceren −
waiting for update Generated random number: 2 Notification issued Obtained random number 2 Generated random number: 5 Notification issued waiting for update Obtained random number 5 Generated random number: 1 Notification issued waiting for update Obtained random number 1 Generated random number: 9 Notification issued waiting for update Obtained random number 9 Generated random number: 2 Notification issued waiting for update Obtained random number 2 Done
Python
- Vragen en antwoorden over Master Python-interviews – uw ultieme voorbereidingsgids
- Python beheersen:6 effectieve manieren om het kwadraat van een getal te berekenen
- Python - E-mail verzenden met SMTP
- Python time.sleep():voeg vertraging toe aan uw code (voorbeeld)
- PyUnit-zelfstudie:Python Unit Testing Framework (met voorbeeld)
- Python RegEx
- Python-recursie
- Python-iterators
- Master Python-metaprogrammering:geavanceerde metaclass-technieken
- Python strftime()
- Kopieer bestand in Python:shutil.copy(), shutil.copystat() methode