8.11. 异步迭代器

异步迭代器 是迭代器的 asyncio 版本。Python 概述 介绍了同步迭代器协议——__iter____next__——以及驱动它的 for 循环。异步迭代器在每一步中添加了一个 await,使迭代器能够在产出各个值之间 等待,而不阻塞事件循环。

8.11.1. 协议

当一个类实现了以下方法时,它就是一个异步迭代器

  • __aiter__(self)——返回迭代器对象,通常是 self

  • async def __anext__(self)——返回下一个值,或在没有更多值时抛出 StopAsyncIteration

相应的循环结构是 async for:

import asyncio


class FrameCounter:
    """Yield N integers, one per frame period."""

    def __init__(self, n, period_ms):
        self._n = n
        self._period_ms = period_ms
        self._i = 0

    def __aiter__(self):
        return self

    async def __anext__(self):
        if self._i >= self._n:
            raise StopAsyncIteration
        await asyncio.sleep_ms(self._period_ms)
        self._i += 1
        return self._i

async def main():
    async for n in FrameCounter(5, 200):
        print(n)

async for 循环会等待每一次对 __anext__ 的调用,因此运行该循环的协程会在产出各个值之间将控制权交还给事件循环,就像任何其他 await 一样。

8.11.2. 何时使用它

当应用程序拥有一个 随时间陆续到达 数据的数据源,且消费者应当惰性地遍历它时。一个每周期产生一个采样的传感器、一个传递消息的网络套接字、一个帧生成器——凡是符合 while True: x = await source.next(); process(x) 这种形式的地方,async for x in source 都是更简洁的写法。

对于会发出数据直到某个有限的结束条件的数据源,迭代器会抛出 StopAsyncIterationasync for 随之正常退出。对于永不结束的数据源——例如连续的传感器数据流、长时间运行的订阅——循环会一直运行,直到它所在的协程被取消或其任务被销毁。