Python asyncio异步迭代器与异步生成器实战
请分别实现一个异步迭代器(实现__aiter__/__anext__)和一个异步生成器(async generator),用于异步分页读取大量数据(如数据库分页查询)。说明async for的底层机制、StopAsyncIteration的作用,以及异步生成器如何利用yield实现惰性求值。
回答
孤独的心
异步迭代器:
class AsyncPaginator:
def __init__(self, fetch_page, page_size=10):
self.fetch_page = fetch_page
self.page_size = page_size
self.page = 0
self.buffer = []
def __aiter__(self):
return self
async def __anext__(self):
if not self.buffer:
self.page += 1
data = await self.fetch_page(self.page, self.page_size)
if not data:
raise StopAsyncIteration
self.buffer = data
return self.buffer.pop(0)
async def main():
async for item in AsyncPaginator(fetch_from_db, 10):
print(item)
异步生成器(更简洁):
async def async_paginate(fetch_page, page_size=10):
page = 0
while True:
page += 1
data = await fetch_page(page, page_size)
if not data:
break
for item in data:
yield item
async def main():
async for item in async_paginate(fetch_from_db):
print(item)
底层机制:
async for自动调用__aiter__()获取异步迭代器- 在每个循环中调用
__anext__(),await结果 - 直到
StopAsyncIteration被raise - 异步生成器自动实现了
__aiter__和__anext__
anext()内置函数(Python 3.10+):await anext(async_iter)等价于手动调用__anext__。
惰性求值:异步生成器每次yield后挂起,不会一次性加载所有数据到内存。