Reading code: CPython's asyncio
I took a closer look at CPython’s asyncio lib. This is not a coherent text, but rather a table of contents with short summaries and pointers into the code1. I simplify by looking only at a subset of the API and skipping a lot of parameters and corner cases.
- runners.py: high-level API that takes care of running a coroutine
def run
: convenience method for using theRunner
class Runner
: context manager that creates event loop and takes care of closing itdef run
: callsrun_until_complete
with given coroutine on event loop
- base_events.py
class BaseEventLoop
: base implementation ofAbstractEventLoop
self._ready
: a simplecollections.deque()
queueself._scheduled
: heap queue (priority queue) for timer handlesdef _call_soon
: appends toself._ready
queue, called byTask
to run__step
as callbackdef call_at
: pushes to heap queuedef create_task
: creates a newTask
object, which (in its__init__
method) puts the first computation step of its coroutine on the event loop’s ready queuedef run_forever
: run loop untilstop()
is calleddef _run_once
: runs one iteration of event loop, appends ready scheduled tasks to ready queue, pops handle from queue and calls its_run()
method
def stop
: setsself._stopping = True
, which is the break condition inrun_forever()
- tasks.py
class Task
: wrapper around a coroutine, suspends execution of coroutine if waiting onFuture
, inherits fromFuture
def __init__
: callsdef call_soon
on event loop withself.__step()
as callback functiondef __step
: runs one step of the coroutine, used as a callback that is wrapped in aHandle
and added to the_ready
queuedef __step_run_and_handle_result
: usessend
andthrow
methods of the coroutine (PEP 343), passes the next__step
to the event loop’scall_soon
method
- def set_result:
Task
inherits fromFuture
, but results (and exceptions) are set by the__step
method on thesuper()
object and this method raises an exception, so that the user does not try to set the result manually
def sleep
: coroutine that completes after given timedef __sleep0
: bare yield: when awaited, event loop does one more iteration until it jumps out of__sleep0
def gather
: coroutines/tasks are wrapped in a_GatheringFuture
, which allows to cancel all childrendef _done_callback
: error handling, collecting results
- futures.py: defines
Future
class, not thread-safedef __await__
: tells Task to wait for completion if not done or returnsdef result()
def cancel
: cancel future and schedule callbacks previously registered byadd_done_callback()
def add_done_callback
: appends a done callbackdef set_result
: set result ofFuture
- events.py: coroutine wrapper classes and some interfaces
class Handle
: wrapper around a callback functionclass TimerHandle
: inherits from Handle, can be sorted by scheduled time
I link to the latest commit at the time of writing.↩︎