Reputation: 89
I'm new to Python asyncio and I'm doing some experiments. I have the following code:
async def say_after(n, s):
await asyncio.sleep(n)
print(s)
async def main():
task1 = asyncio.create_task(say_after(2, 'a'))
task2 = asyncio.create_task(say_after(1, 'b'))
await task1
print('x', flush=True)
await task2
print('y', flush=True)
asyncio.run(main())
And the output:
b
a
x
y
I don't understand the order here. Can someone help explain? Especially why x comes after b and a?
Upvotes: 5
Views: 429
Reputation: 55
await task1
basically says that do not execute the next lines of code until task1
is finished (i.e. the execution of say_after(2, 'a')
).
task1
takes longer than task2
to execute, so by the time you "awaited" task1
, task2
is already finished executing. So putting await task2
below await task1
is somewhat useless here. If you swap these two lines, the output will be different.
That's why 'b'
is printed before 'a'
. And not until 'a'
is printed, 'x'
and 'y'
could be printed.
Upvotes: 0
Reputation: 6780
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.
Upvotes: 1
Reputation: 27012
Especially why x comes after b and a?
b
is printed in task2
about 1 second after the start of main
, and a
is printed in task1
about 2 seconds after the start of main
. The await task1
waits for task1
, and so waits about 2 seconds. So by the time await task1
completes, both b
and a
would have been printed.
(The "about"s in the above are deliberate... there would be variations, but in most situations, they would be small)
Upvotes: 0