Why we need the `Asyncio.sleep` to start the loop?

2019-08-03 17:23发布

问题:

In this document of Asyncio, we can see it use await asyncio.sleep(1) to delay 1 second and then cancel the task.

And I try to change it to await asyncio.sleep(0), it works well too.

But when I try to delete await asyncio.sleep(1), the program seems wouldn't enter the func cancel_me. So it just appear main(): cancel_me is cancelled now in the cli.

What is the reason for this?

回答1:

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:

  1. await asyncio.sleep(0) as well as 1 will return control to event loop
  2. Event loop will start to execute cancel_me()
  3. cancel_me() eventually will stumble on something blocking and return control back to event loop
  4. Event loop will resume execution of main()
  5. 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.