对Python异步生成器(asyncio)执行行为的困惑求助
异步生成器执行逻辑误区解析
先看这段模拟远程数据库取值的代码:
import asyncio async def async_gen(): for i in range(5): print(f"entering iteration {i}") await asyncio.sleep(3) print(f"ending iteration {i}") yield i async def main(): async for value in async_gen(): print(value) asyncio.run(main())
预期vs实际差异
- 预期:所有
entering iteration i瞬间打印,3秒后所有ending iteration i和数值依次输出,总耗时3秒。 - 实际:每次迭代的
entering和ending间隔3秒,5次迭代总耗时15秒,输出是逐次完成的。
核心误区:异步生成器不是并发执行
异步生成器的async for是顺序迭代的:
- 第一次
async for触发async_gen()执行,走到yield i时暂停,返回值0; - 打印
0后,第二次async for才会让async_gen()从暂停处继续执行下一轮循环; - 每一轮循环里的
await asyncio.sleep(3)会阻塞当前迭代的执行,直到休眠完成,才会进入下一次迭代。
简单说:异步生成器的迭代是串行的,前一次迭代没走完,下一次不会开始,自然没法实现你想要的并发效果。
实现预期效果的正确方式
如果要让多个取值任务并发执行,应该用asyncio.gather来批量调度异步任务,代码如下:
import asyncio async def fetch_data(i): print(f"entering iteration {i}") await asyncio.sleep(3) print(f"ending iteration {i}") return i async def main(): # 创建所有异步任务 tasks = [fetch_data(i) for i in range(5)] # 并发执行所有任务,等待全部完成后获取结果 results = await asyncio.gather(*tasks) for result in results: print(result) asyncio.run(main())
这段代码的执行逻辑:
- 所有
fetch_data任务会被同时提交给事件循环,瞬间打印所有entering iteration i; - 3秒后所有休眠同时结束,依次打印
ending iteration i和对应的结果,总耗时仅3秒,完全符合预期。
内容的提问来源于stack exchange,提问作者Youcef Kacer
相关产品推荐
相关产品推荐

