Executing say_after
(without await
) creates a coroutine object, but does not start it yet.
If you await
on the coroutine object, then you are executing the coroutine until the Python encounters one of await
or return
(or end of function) in the coroutine. "Executing" here means transforming the coroutine into a Task
object and put that object in the async loop.
However, create_task
immediately 'starts' the coroutine and put them tasks in the async loop (though, because this is async instead of parallel, execution does not actually begin until Python encounters await
in main()
).
In your situation, as soon as Python sees the await task1
, it 'leaves' main() and loops among task1
and task2
back and forth (because both tasks have been put in the async loop by create_task) until task1
is completed (because task1 is the one being await-ed on). Because task2 had scheduled itself to wait for a shorter time, it finishes first. About 1 second later, task1 completes, and only then execution returns to main() (because, remember, it was task1 that main() had been await-ing on).
At this point, both task1 and task2 has completed; the await task2
line practically does nothing; it's just "wrapping up" task2 and (almost) immediately returns.