The behavior of async functions is different even though they are almost the same code, but I don't understand why.
My code is:
import asyncio
async def func1():
await asyncio.sleep(1)
print("func1")
async def func2():
await asyncio.sleep(time)
print("func2")
async def func3():
await asyncio.sleep(3)
print("func3")
async def main():
asyncio.create_task(func1())
await func2()
await func3()
asyncio.run(main())
If I put time = 1 then the output is:
func2
func1
func3
But if time = 2 then the output is:
func1
func2
func3
In the first case, why is func2 printed before func1 even though func2 starts late?
No matter how you get
timeintofunc2, the difference is clearly between how you startfunc1andfunc2:You create the task, and then instantly await
func2. Then, whenfunc2goes to sleep,func1has a chance to start, and also goes to sleep.If
func2finds thattime == 1, it wakes up after one second and prints, and then after thatfunc1wakes up, just a fraction later.If
func2finds thattime == 2, it only wakes up after two seconds, andfunc1will have woken up before it.Your question was "In the first case, why is func2 printed before func1 even though func2 starts late?" - you assume
func2"starts late", but it doesn't. It is awaited before the task created withfunc1. You never explicitly await the task, and your program could complete without the task ever completing, but since you havefunc3there, waiting substantially longer, you're almost guaranteed it will.You would have found the order doesn't change when you do this:
Because then the two asynchronous functions are awaited in order, and will complete in order when provided with the same
sleep()time.Similarly, with:
The order is as you expect it, since the task is explicitly awaited before
func2()is started and awaited.Or of course, just:
A good editor or IDE will warn you, if you don't await
create_task. PyCharm warns: "Co-routine create_task is not awaited".The documentation has this to say: "Important: Save a reference to the result of this function, to avoid a task disappearing mid-execution. The event loop only keeps weak references to tasks. A task that isn’t referenced elsewhere may get garbage collected at any time, even before it’s done. For reliable “fire-and-forget” background tasks, gather them in a collection."