8.7. Események¶
Az asyncio.Event a legegyszerűbb jelzési primitív, amelyet a modul kínál. Az egyik korutin beállít egy eseményt, amikor valami megtörtént; tetszőleges számú más korutin várja, hogy az esemény beállításra kerüljön, mielőtt folytatná. Nincs hasznos terhelés – egy esemény egy boolean, amely bekapcsol, és bekapcsolva marad, amíg valami törli.
8.7.1. Az alapforma¶
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())
A váró feladat fut, eléri az await evt.wait()-et, és felfüggesztésre kerül – az esemény törölt állapotban indul, így a wait hívás visszaadja a vezérlést a huroknak. Egy másodperccel később a main meghívja az evt.set()-et, és a váró feladat ütemezésre kerül a folytatáshoz. A záró await asyncio.sleep(0) csak egy yield, hogy a hurok esélyt kapjon a váró feladat futtatására, mielőtt a main visszatér.
8.7.2. A négy metódus¶
set()– beállítja az eseményt, és beütemezi az összes, jelenleg await()-en blokkolt korutint a folytatáshoz. Az esemény beállítva marad, amíg nem törlik.clear()– visszaállítja az eseményt törölt állapotba. Azok a korutinok, amelyek ezutánawait wait()-elnek, ismét blokkolódni fognak.wait()– egy korutin. Ha az esemény már be van állítva, azonnal visszatér. Egyébként blokkol, amíg valami be nem állítja.is_set()– blokkolás nélkül visszaadja az aktuális állapotot. Hasznos, amikor egy korutin ellenőrizni akarja az eseményt anélkül, hogy várna rá.
8.7.3. Több váró¶
Több korutin is await-elheti ugyanazt az eseményt. Amikor valami meghívja a set()-et, mindegyik ütemezésre kerül a folytatáshoz. Az esemény alapértelmezetten egy-a-többhöz; nincs szükség több eseményre ahhoz, hogy több várónak szétoszoljon.
8.7.4. Egy esemény újrafelhasználása¶
Gyakori minta, hogy egy eseményt ismételten használnak – egy korutin, amely jelenként egyszer fut – úgy, hogy minden menet után törlik:
async def worker(go):
while True:
await go.wait()
do_one_unit_of_work()
go.clear()
A termelő beállítja az eseményt, valahányszor van munka; a munkás törli, amint felvette a jelet. Ha a termelő esetleg újra beállítaná az eseményt, mielőtt a munkás felébredt volna, a munkás kezelni szeretheti ezt az esetet (while go.is_set(): ...), mielőtt törölné.
8.7.5. Biztonságos kontextusok¶
Az Event-en nem biztonságos a set() hívása megszakításkezelőn belülről. A mechanizmus, amelyet a várók ütemezésére használ, feltételezi, hogy az eseményhurok saját kontextusán belül fut, ami a megszakításokra nem igaz. Egy asyncio-feladat megszakításkezelőből való felébresztéséhez az ThreadSafeFlag (amelyet hamarosan tárgyalunk) a megfelelő primitív.