Python中的异步生成器与异步推导式
字数 1976 2025-12-10 14:34:01
Python中的异步生成器与异步推导式
1. 知识点描述
在Python中,异步生成器是使用async def定义、并包含yield语句的协程函数,用于异步生成值序列。异步推导式是类似列表推导式的语法,但通过async for迭代异步可迭代对象,生成列表、集合、字典等集合。这两者是异步编程中处理流式数据或异步集合操作的核心工具,常用于asyncio环境中高效处理I/O密集型任务。
2. 异步生成器的核心机制
2.1 基本语法
异步生成器函数通过async def定义,并在函数体内使用yield返回数据:
async def async_gen():
for i in range(3):
await asyncio.sleep(0.1) # 模拟异步操作
yield i
- 调用
async_gen()不会执行函数体,而是返回一个异步生成器对象(类型为async_generator)。 - 异步生成器实现了异步迭代器协议,即需通过
__aiter__()和__anext__()方法支持异步迭代。
2.2 异步迭代协议
异步生成器对象的核心方法:
__aiter__():返回自身(异步迭代器)。__anext__():在每次迭代时恢复生成器执行,返回一个awaitable对象(通常是协程),解析后得到yield的值。若生成器结束,抛出StopAsyncIteration异常。
示例:手动迭代异步生成器
import asyncio
async def consume_async_gen():
ag = async_gen() # 创建异步生成器对象
async for value in ag: # 使用 async for 迭代
print(value) # 输出 0, 1, 2
3. 异步推导式的工作原理
3.1 异步推导式的类型
Python支持四种异步推导式(语法在async for前放置集合类型):
- 异步列表推导式:
[i async for i in async_gen()] - 异步集合推导式:
{i async for i in async_gen()} - 异步字典推导式:
{i: i*2 async for i in async_gen()} - 异步生成器表达式:
(i async for i in async_gen())
3.2 执行过程
以异步列表推导式为例:
async def demo():
data = [i async for i in async_gen()] # 结果: [0, 1, 2]
执行步骤:
- 解释器识别
async for语法,创建隐式的异步迭代循环。 - 循环内部:
- 调用异步生成器的
__anext__(),返回awaitable对象。 - 通过
await等待该对象,获取值i。 - 将
i加入临时列表。
- 调用异步生成器的
- 当
StopAsyncIteration抛出时,结束循环并返回完整列表。
4. 与同步版本的对比
| 特性 | 同步生成器/推导式 | 异步生成器/推导式 |
|---|---|---|
| 定义关键字 | def + yield |
async def + yield |
| 迭代方式 | for循环 |
async for循环 |
| 推导式语法 | [i for i in gen()] |
[i async for i in async_gen()] |
| 暂停机制 | 遇yield暂停,保存本地状态 |
在yield和await处均可暂停 |
5. 实际应用场景
场景1:异步流式数据处理
import aiohttp
async def fetch_urls(urls):
async with aiohttp.ClientSession() as session:
for url in urls:
async with session.get(url) as resp:
yield await resp.text() # 异步生成每个页面内容
# 使用异步推导式收集数据
async def collect_pages(urls):
pages = [text async for text in fetch_urls(urls)] # 并发请求并收集结果
return pages
场景2:异步过滤与转换
# 异步生成器表达式作为过滤管道
async def filter_data(source_gen):
filtered = (item.upper() async for item in source_gen if item.startswith("A"))
async for val in filtered: # 惰性计算
process(val)
6. 注意事项与常见错误
-
必须使用
async for迭代:
错误:for i in async_gen()(同步循环无法驱动)。
正确:async for i in async_gen()。 -
异步推导式需在协程函数内使用:
异步推导式本身返回awaitable对象,需在协程中解析:async def main(): data = [i async for i in async_gen()] # 直接返回列表 # 若在非协程中使用,需用asyncio.run()包装 -
资源管理:
异步生成器中可使用async with管理资源(如数据库连接),确保yield前后资源正确释放:async def read_lines(connection): async with connection.cursor() as cur: await cur.execute("SELECT * FROM table") async for row in cur: yield row
7. 底层实现简析
- 异步生成器对象由
PyAsyncGenObject结构体表示,内部状态机跟踪yield和await位置。 - 异步推导式在字节码层面生成
GET_AITER、SET_ANEXT等指令,通过事件循环驱动迭代。 - 异步生成器最终需调用
aclose()关闭,防止资源泄漏(通常由async for自动处理)。
8. 总结
- 异步生成器通过
async def和yield结合,实现惰性的异步数据流。 - 异步推导式提供简洁语法,支持对异步可迭代对象进行集合转换。
- 两者均依赖
async for驱动,是异步编程中处理批量I/O操作的高效工具。