Python's asyncio is usually introduced through its public API: define a coroutine with async def, suspend it with await, and run several operations concurrently with create_task() or gather(). That is enough to write useful programs, but it does not explain why those programs behave as they do.

The difficult questions sit below the API:

Why does one blocking function stall every coroutine on the loop?

What resumes a coroutine after an await?

Why is cancellation cooperative rather than immediate?