8.7. Evenimente¶
asyncio.Event este cea mai simplă primitivă de semnalizare pe care o oferă modulul. O corutină setează un eveniment atunci când s-a întâmplat ceva; orice număr de alte corutine așteaptă ca evenimentul să fie setat înainte de a continua. Nu există niciun conținut util – un eveniment este un boolean care se comută pe activ și rămâne activ până când ceva îl șterge.
8.7.1. Forma de bază¶
import asyncio
async def waiter(evt):
print("waiting")
await evt.wait()
print("got signal")
async def main():
evt = asyncio.Event()
asyncio.create_task(waiter(evt))
await asyncio.sleep(1)
evt.set()
await asyncio.sleep(0)
asyncio.run(main())
Sarcina care așteaptă rulează, ajunge la await evt.wait() și este suspendată – evenimentul începe în starea ștearsă, astfel încât apelul wait cedează controlul înapoi buclei. O secundă mai târziu, main apelează evt.set() și sarcina care așteaptă este programată să se reia. await asyncio.sleep(0) final este doar o cedare, astfel încât bucla să aibă șansa de a rula sarcina care așteaptă înainte ca main să returneze.
8.7.2. Cele patru metode¶
set()– comută evenimentul pe setat și programează fiecare corutină blocată în prezent pewait()să se reia. Evenimentul rămâne setat până la ștergere.clear()– comută evenimentul înapoi pe șters. Corutinele care așteaptă cuawait wait()ulterior se vor bloca din nou.wait()– o corutină. Dacă evenimentul este deja setat, returnează imediat. Altfel se blochează până când ceva îl setează.is_set()– returnează starea curentă fără a se bloca. Util atunci când o corutină dorește să verifice evenimentul fără a-l aștepta.
8.7.3. Mai mulți așteptători¶
Mai multe corutine pot aștepta cu await același eveniment. Atunci când ceva apelează set(), toate sunt programate să se reia. Evenimentul este unul-la-mulți în mod implicit; nu este nevoie de mai multe evenimente pentru a distribui către mai mulți așteptători.
8.7.4. Reutilizarea unui eveniment¶
Un tipar frecvent este folosirea unui eveniment în mod repetat – o corutină care rulează o dată per semnal – ștergându-l după fiecare trecere:
async def worker(go):
while True:
await go.wait()
do_one_unit_of_work()
go.clear()
Producătorul setează evenimentul ori de câte ori există muncă; lucrătorul îl șterge după ce a preluat semnalul. Dacă producătorul ar putea seta evenimentul din nou înainte ca lucrătorul să se fi trezit, lucrătorul ar putea dori să gestioneze acel caz (while go.is_set(): ...) înainte de ștergere.
8.7.5. Contexte sigure¶
Event nu este sigur de apelat set() din interiorul unui gestionar de întreruperi. Mecanismul pe care îl folosește pentru a programa așteptătorii presupune că rulează în interiorul contextului propriu al buclei de evenimente, ceea ce întreruperile nu sunt. Pentru a trezi o sarcină asyncio dintr-un gestionar de întreruperi, ThreadSafeFlag (acoperit în curând) este primitiva potrivită.