异步生成器必须用 async for 遍历,因其仅实现 aiter 和 __anext__,不支持普通 __iter__;async for 用于流式 i/o、websocket 推送、数据库游标等场景,需注意 python 3.6+ 兼容性及中断时的资源清理。

异步生成器不能用普通 for 遍历,必须用 async for;否则会报 TypeError: 'AsyncGenerator' object is not iterable。
为什么 async for 不是可选而是强制?
异步生成器返回的是 AsyncGenerator 对象,它不实现 __iter__,只实现 __aiter__。普通 for 会调用前者,而事件循环需要通过 __anext__ 才能 await 每次 yield 后的挂起点。
常见错误现象:
- 直接写
for item in async_gen(): ...→ 立刻崩溃 - 误以为加了
await就行,写成await for item in async_gen(): ...→ 语法错误 - 在非
async def函数里尝试async for→SyntaxError: 'async for' outside async function
async for 的实际使用场景有哪些?
典型用于流式 I/O 或实时数据消费,比如:
- 用
aiofiles.open()逐块读大文件,配合async for chunk in file_reader: - FastAPI 中
StreamingResponse底层依赖异步生成器,路由函数里用async for拉取数据 - WebSocket 推送时,
async for update in stock_price_generator("AAPL"):持续发消息 - 数据库游标流式查询(如
asyncpg),避免一次性加载全部结果集
参数和兼容性要注意什么?
async for 本身没有参数,但它的行为高度依赖所迭代对象是否真正实现了异步迭代协议:
- 必须是返回
AsyncGenerator或带__aiter__/__anext__的对象;普通生成器、列表、range都不行 - Python 版本要求:3.6+ 支持基本语法,但 3.11+ 才支持
async with和async for在try/except中的完整异常传播语义 - 不能和
break/continue混用在未完成的await调用后——比如async for循环中途return,可能跳过__aexit__清理逻辑
示例片段(正确写法):
async def fetch_chunks():
async with aiofiles.open("log.bin", "rb") as f:
while True:
chunk = await f.read(8192)
if not chunk:
break
yield chunk
<p>async def process_stream():
async for chunk in fetch_chunks(): # ✅ 必须这样写
process(chunk) # 处理每一块</p>
容易被忽略的清理与中断问题
异步生成器不像同步生成器那样能靠 finally 保证资源释放——如果消费者提前退出(比如客户端断开 WebSocket、HTTP 请求中止),async for 循环可能被中断,而生成器内部的 async with 或 await cleanup() 不一定执行。
关键点:
- 不要依赖生成器函数末尾的
await close_resource();应把清理逻辑放在async with块内,或显式捕获GeneratorExit(但注意:Python 不保证异步生成器收到该信号) - 在 FastAPI 的
StreamingResponse场景中,需监听客户端断连,主动raise StopAsyncIteration或用try/except ClientDisconnect - 若生成器内部有长耗时
await(如asyncio.sleep(30)),中断可能延迟数秒才生效,这不是 bug,是事件循环调度特性
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











