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 является более чистым вариантом.

Для источников, выдающих данные до конечного условия завершения, итератор возбуждает StopAsyncIteration, и async for завершается штатно. Для источников, которые никогда не заканчиваются – непрерывный поток с датчика, долго работающая подписка – цикл выполняется до тех пор, пока не будет отменена корутина, в которой он находится, или не будет уничтожена её задача.