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 pe wait() să se reia. Evenimentul rămâne setat până la ștergere.

  • clear() – comută evenimentul înapoi pe șters. Corutinele care așteaptă cu await 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ă.