Python异步协程与生成器:能否用两个协程分别迭代异步生成器并等待其终止?
问题解答
你不能按照示例中的方式实现需求,核心有两个问题:
1. 异步生成器不是可等待对象,直接await gen会报错
异步生成器实现的是__aiter__和__anext__接口,用于支持async for迭代;而await要求对象必须是可等待对象(实现__await__方法,或是协程、任务、Future实例)。直接await异步生成器实例会触发TypeError: cannot await an async generator。
你的示例代码首先要修正协程定义的语法(添加async def),但即使修正后,coro2里的await gen依然会报错。
2. 同一个异步生成器不能被多个协程同时操作
异步生成器的内部状态是单线程维护的,每次async for迭代都会调用__anext__推进状态。如果两个协程同时操作同一个生成器实例,会导致状态错乱,迭代逻辑完全失控——比如一个协程刚推进到某一步,另一个协程又调用__anext__,破坏生成器的执行流程。
正确实现方式
如果想让一个协程等待异步生成器的迭代终止,应该等待负责迭代的协程任务完成,或者用同步原语(如asyncio.Event)来传递迭代完成的信号。
方式一:等待迭代协程任务
import asyncio async def async_gen(): # 示例异步生成器 for i in range(3): yield i await asyncio.sleep(0.5) async def coro1(gen): async for _ in gen: await asyncio.sleep(1) print("coro1 处理了一个元素") async def coro2(iter_task): await iter_task # 等待迭代协程完成 print('生成器迭代完成') async def main(): gen = async_gen() # 创建迭代协程的任务 iter_task = asyncio.create_task(coro1(gen)) # 让coro2等待这个任务结束 await coro2(iter_task) asyncio.run(main())
方式二:用asyncio.Event通知完成
import asyncio async def async_gen(): for i in range(3): yield i await asyncio.sleep(0.5) async def coro1(gen, done_event): async for _ in gen: await asyncio.sleep(1) print("coro1 处理了一个元素") done_event.set() # 迭代完成后触发事件 async def coro2(done_event): await done_event.wait() # 等待迭代完成的信号 print('生成器迭代完成') async def main(): gen = async_gen() done_event = asyncio.Event() # 同时运行两个协程 await asyncio.gather( coro1(gen, done_event), coro2(done_event) ) asyncio.run(main())
内容的提问来源于stack exchange,提问作者flotschi
相关产品推荐
相关产品推荐

