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 onwait()to resume. The event stays set until cleared.clear()– flip the event back to cleared. Coroutines thatawait 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.