11.7. Events

asyncio.Event is the simplest signalling primitive the module provides. One coroutine sets an event when something has happened; any number of other coroutines wait for the event to be set before continuing. There is no payload – an event is a boolean that flips on and stays on until something clears it.

11.7.1. The basic shape

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

The waiter task runs, hits await evt.wait(), and is suspended – the event starts in the cleared state, so the wait call yields back to the loop. A second later main calls evt.set() and the waiter is scheduled to resume. The trailing await asyncio.sleep(0) is just a yield so the loop gets a chance to run the waiter before main returns.

11.7.2. The four methods

  • set() – flip the event to set, and schedule every coroutine currently blocked on wait() to resume. The event stays set until cleared.

  • clear() – flip the event back to cleared. Coroutines that await wait() afterwards will block again.

  • wait() – a coroutine. If the event is already set, returns immediately. Otherwise blocks until something sets it.

  • is_set() – returns the current state without blocking. Useful when a coroutine wants to check the event without waiting on it.

11.7.3. Multiple waiters

Several coroutines can await the same event. When something calls set() they are all scheduled to resume. The event is one-to-many by default; there is no need for several events to fan out to several waiters.

11.7.4. Reusing an event

A common pattern is to use an event repeatedly – a coroutine that runs once per signal – by clearing it after each pass:

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

The producer sets the event whenever there is work; the worker clears it once it has picked up the signal. If the producer might set the event again before the worker has woken up, the worker may want to handle that case (while go.is_set(): ...) before clearing.

11.7.5. Safe contexts

Event is not safe to call set() on from inside an interrupt handler. The mechanism it uses to schedule waiters assumes it is running inside the event loop’s own context, which interrupts are not. For waking an asyncio task from an interrupt handler, ThreadSafeFlag (covered shortly) is the right primitive.