这5个await不是"5个独立任务",而是同一个协程里的5个"暂停点";只有用create_task()创建出来的才是独立任务,事件循环才会在它们之间切换调度。
🔑 核心区分:await是暂停点,create_task()才是创建任务
-
情况一:串行await(不是并发)
如果在一个协程里顺序写5个await,事件循环会一个一个按顺序执行 ,前一个完成后才执行下一个,这本质上还是串行的:pythonasync def main(): result1 = await task_a() # 等task_a完成,才往下走 result2 = await task_b() # 等task_b完成,才往下走 result3 = await task_c() result4 = await task_d() result5 = await task_e() -
情况二:用
create_task()创建5个独立任务(真正的并发)
这才是你描述的场景。事件循环会同时启动这5个任务,谁先完成就先拿到谁的结果:pythonasync def main(): t1 = asyncio.create_task(task_a()) t2 = asyncio.create_task(task_b()) t3 = asyncio.create_task(task_c()) t4 = asyncio.create_task(task_d()) t5 = asyncio.create_task(task_e()) # 5个任务同时在跑,谁先完成谁先返回 r1 = await t1 r2 = await t2 # ...
⚙️ 事件循环的调度过程
以5个独立任务为例,事件循环的调度流程如下:
- 5个任务被注册到事件循环的就绪队列
- 事件循环取出任务A开始执行,遇到
await(比如网络请求),任务A暂停,进入等待队列 - 事件循环取出任务B开始执行,遇到
await,任务B也暂停 - 依次类推,5个任务都暂停在各自的
await处 - 此时事件循环监听I/O事件,哪个任务的I/O先完成(比如某个HTTP请求先返回了),就把那个任务移回就绪队列
- 事件循环恢复那个任务,从
await的下一行继续执行
核心总结 :不是事件循环"安排顺序",而是谁先完成谁先被恢复,完全取决于I/O操作的实际完成时间。
📦 收集结果的三种方式
asyncio.gather():等所有任务完成,按传入顺序返回结果列表(不管实际完成顺序)asyncio.wait():更灵活,可以设置"第一个完成就返回"或"全部完成才返回"asyncio.as_completed():谁先完成就先拿到谁的结果,按完成顺序返回
python
# 按完成顺序拿结果(最符合你的描述)
for coro in asyncio.as_completed([task_a(), task_b(), task_c(), task_d(), task_e()]):
result = await coro
print(f"拿到结果: {result}") # 先完成的先打印
📌 一句话总结
await是"暂停点",create_task()是"创建独立任务",事件循环是"调度员"------它不安排顺序,而是谁先完成就先处理谁。