8.7. Události¶
asyncio.Event je nejjednodušší signalizační primitivum, které modul poskytuje. Jedna korutina událost nastaví, když se něco stalo; libovolný počet jiných korutin čeká, až bude událost nastavena, než budou pokračovat. Není zde žádný náklad (payload) – událost je booleovská hodnota, která se překlopí na zapnuto a zůstane zapnutá, dokud ji něco nevymaže.
8.7.1. Základní tvar¶
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())
Úloha čekatele běží, narazí na await evt.wait() a je pozastavena – událost začíná ve vymazaném stavu, takže volání wait předá řízení zpět smyčce. O sekundu později main zavolá evt.set() a čekatel je naplánován k obnovení. Závěrečné await asyncio.sleep(0) je jen yield, aby smyčka dostala šanci spustit čekatele předtím, než se main vrátí.
8.7.2. Čtyři metody¶
set()– překlopí událost na nastaveno a naplánuje obnovení každé korutiny aktuálně blokované nawait(). Událost zůstává nastavena, dokud není vymazána.clear()– překlopí událost zpět na vymazáno. Korutiny, které potéawait wait(), budou opět blokovat.wait()– korutina. Pokud je událost již nastavena, vrátí se okamžitě. Jinak blokuje, dokud ji něco nenastaví.is_set()– vrací aktuální stav bez blokování. Užitečné, když chce korutina událost zkontrolovat, aniž by na ni čekala.
8.7.3. Více čekatelů¶
Několik korutin může awaitovat na stejnou událost. Když něco zavolá set(), jsou všechny naplánovány k obnovení. Událost je ve výchozím nastavení jeden-k-mnoha; není potřeba mít několik událostí, aby se rozvětvily k několika čekatelům.
8.7.4. Opětovné použití události¶
Běžným vzorem je používat událost opakovaně – korutina, která běží jednou na signál – jejím vymazáním po každém průchodu:
async def worker(go):
while True:
await go.wait()
do_one_unit_of_work()
go.clear()
Producent událost nastaví, kdykoli je práce; pracovník ji vymaže, jakmile signál vyzvedne. Pokud by producent mohl událost nastavit znovu předtím, než se pracovník probudil, může chtít pracovník tento případ ošetřit (while go.is_set(): ...) před vymazáním.
8.7.5. Bezpečné kontexty¶
Na Event není bezpečné volat set() zevnitř obslužné rutiny přerušení. Mechanismus, který používá k plánování čekatelů, předpokládá, že běží uvnitř vlastního kontextu smyčky událostí, čímž přerušení nejsou. Pro probuzení asyncio úlohy z obslužné rutiny přerušení je správným primitivem ThreadSafeFlag (probráno zanedlouho).