asyncio
coroutines aren't executed by themselves, they're executed by event loop.
Event loop receives control on asyncio.run
and starts to execute some coroutine. When execution flow reaches something blocking like await asyncio.sleep()
or await future
it return control back to event loop. It allows event loop to start or resume execution of something else.
Take a look at example and picture here to see it on simple example.
In the example about cancel()
following happen:
await asyncio.sleep(0)
as well as 1
will return control to event loop
- Event loop will start to execute
cancel_me()
cancel_me()
eventually will stumble on something blocking and return control back to event loop
- Event loop will resume execution of
main()
main()
will mark task to be cancelled with task.cancel()
and await it cancelled with await task
If you however don't have asyncio.sleep()
on step one, execution flow won't even reach cancel_me()
because event loop never received control between tasks creation and task cancellation. When event loop reaches await task
it sees task was never started and mark for cancellation: there's no sense to start it now.