8.7. Händelser

asyncio.Event är den enklaste signaleringsprimitiv modulen tillhandahåller. En coroutine sätter en händelse när något har inträffat; ett godtyckligt antal andra coroutiner väntar på att händelsen ska sättas innan de fortsätter. Det finns ingen nyttolast – en händelse är en boolesk som slås på och förblir på tills något nollställer den.

8.7.1. Grundformen

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())

Väntaruppgiften körs, träffar await evt.wait() och pausas – händelsen startar i nollställt tillstånd, så wait-anropet lämnar tillbaka till loopen. En sekund senare anropar main evt.set() och väntaren schemaläggs att återupptas. Det avslutande await asyncio.sleep(0) är bara ett yield så att loopen får en chans att köra väntaren innan main returnerar.

8.7.2. De fyra metoderna

  • set() – slå om händelsen till satt och schemalägg varje coroutine som för närvarande är blockerad på wait() att återupptas. Händelsen förblir satt tills den nollställs.

  • clear() – slå om händelsen tillbaka till nollställd. Coroutiner som await wait() därefter kommer att blockeras igen.

  • wait() – en coroutine. Om händelsen redan är satt returnerar den omedelbart. Annars blockerar den tills något sätter den.

  • is_set() – returnerar det aktuella tillståndet utan att blockera. Användbart när en coroutine vill kontrollera händelsen utan att vänta på den.

8.7.3. Flera väntare

Flera coroutiner kan await samma händelse. När något anropar set() schemaläggs de alla att återupptas. Händelsen är en-till-många som standard; det behövs inte flera händelser för att sprida ut till flera väntare.

8.7.4. Att återanvända en händelse

Ett vanligt mönster är att använda en händelse upprepade gånger – en coroutine som körs en gång per signal – genom att nollställa den efter varje varv:

async def worker(go):
    while True:
        await go.wait()
        do_one_unit_of_work()
        go.clear()

Producenten sätter händelsen närhelst det finns arbete; arbetaren nollställer den när den har plockat upp signalen. Om producenten kan sätta händelsen igen innan arbetaren har vaknat kan arbetaren behöva hantera det fallet (while go.is_set(): ...) innan den nollställer.

8.7.5. Säkra kontexter

Event är inte säkert att anropa set() på inifrån en avbrottshanterare. Mekanismen den använder för att schemalägga väntare förutsätter att den körs inuti händelseloopens egen kontext, vilket avbrott inte är. För att väcka en asyncio-uppgift från en avbrottshanterare är ThreadSafeFlag (täcks inom kort) rätt primitiv.