When I run the following asynchronous code:
from asyncio import create_task, sleep, run
async def print_(delay, x):
print(f'start: {x}')
await sleep(delay)
print(f'end: {x}')
async def main():
slow_task = create_task(print_(2, 'slow task'))
fast_task = create_task(print_(1, 'fast task'))
# The order of execution here is strange:
print(0)
await slow_task
print(1)
await fast_task
run(main())
I get an unexpected order of execution:
0
start: slow task
start: fast task
end: fast task
end: slow task
1
What exactly is happening?
What I find strange is print(1)
is ignored until all tasks are finished. To my understanding the code runs as expected until it reaches any await
. Then it creates a task-loop with any other awaitable it finds down the line. Which it prioritizes. Right?
That's what I find surprising. I'd expect it to run print(1)
before any task is complete. Why doesn't it?
Is that the standard behavior or does it vary? If so, what does it vary upon?
If you could into detail how the event loop works alongside the rest of the code, that'd be great.
Let's walk through this:
0
, so this becomes your first output.await slow_task
, passing control to the event loop until slow_task
finishes.
slow_task
, it's prioritized, so it starts first, so start: slow_task
is printed.slow_task
contains an await sleep(2)
, it passes control back to the event loop, which finds fast_task
as ready to operate and starts it, so start: fast_task
is printed.fast_task
's await sleep(1)
finishes first, fast_task
completes, and end: fast_task
is printed. Because we're await
ing slow_task
, not fast_task
, we remain in the event loop.end: slow task
. Because this is what we were await
ing for, control flow is returned to the synchronous process.1
, so this becomes your last output.Everything is exactly as one would expect.
That said, for the more general case, you can't expect order-of-operations in an async program to be reliably deterministic in real-world cases where you're waiting on I/O operations that can take a variable amount of time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With