实验 3:create_task 什么时候开始跑
上一节已经见过 create_task(),但那里只说明它“也能并发”。这一节专门看一个更细的问题:create_task() 调用完以后,任务什么时候真正开始执行?
结论是:create_task() 会把任务排进事件循环。当前协程继续往下跑;等当前协程走到下一个 await,事件循环才有机会去跑刚排进去的任务。
运行:
bash
python3 examples/asyncio_demos/03_create_task_lifecycle.py先看输出顺序
示例里有这几行:
python
profile_task = asyncio.create_task(fetch("profile", 0.3, started))
orders_task = asyncio.create_task(fetch("orders", 0.2, started))
print("main: tasks created")
await asyncio.sleep(0)
print("main: back after sleep(0)")asyncio.sleep(0) 不是业务等待。这里故意写它,是为了让当前协程暂停一下,把执行机会交回事件循环。
你会看到类似这样的顺序:
text
0.000s main: tasks created
0.000s profile: start
0.000s orders: start
0.000s main: back after sleep(0)这说明两件事:
create_task()返回后,fetch()还没有在当前这一行里同步跑完。- 当前协程一遇到
await asyncio.sleep(0),事件循环就能去执行刚才创建的两个 Task。
await task 不是启动任务
创建 Task 是启动安排;await task 是等结果。
python
task = asyncio.create_task(fetch("profile", 0.3))
await do_something_else()
profile = await task这段代码的意思是:先让 fetch() 开始等网络;当前协程去做一点别的事;最后再回来拿 fetch() 的结果。
如果你写成:
python
profile = await fetch("profile", 0.3)
await do_something_else()那 do_something_else() 必须等 fetch() 完成后才能开始。
后台任务留到后面处理
你可能见过这种写法:
python
asyncio.create_task(write_audit_log())这叫“创建了任务但不在这里等待”。它有自己的坑:异常谁处理、程序退出时怎么收尾。这里先不展开,后面的 TaskGroup 和调试章节会专门处理。当前只记住:如果你需要结果,就要在某个地方 await task,或者交给 gather() / TaskGroup 管。
小练习
- 注释掉
await asyncio.sleep(0),观察profile: start会不会仍然出现在main: back after sleep(0)前面。 - 把最后的
await asyncio.gather(...)改成先await profile_task,再await orders_task,观察两个任务是不是仍然同时开始。 - 把两个
create_task()改回连续await fetch(...),比较总耗时。