Skip to content

实验 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)

这说明两件事:

  1. create_task() 返回后,fetch() 还没有在当前这一行里同步跑完。
  2. 当前协程一遇到 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 管。

小练习

  1. 注释掉 await asyncio.sleep(0),观察 profile: start 会不会仍然出现在 main: back after sleep(0) 前面。
  2. 把最后的 await asyncio.gather(...) 改成先 await profile_task,再 await orders_task,观察两个任务是不是仍然同时开始。
  3. 把两个 create_task() 改回连续 await fetch(...),比较总耗时。

面向学习目的的 Python asyncio 中文教程与 mini_asyncio 教学运行时。