8.11. Iteratory asynchroniczne#

Iterator asynchroniczny to asyncio-wa wersja iteratora. W Przeglądzie Pythona przedstawiono synchroniczny protokół iteratora – __iter__ i __next__ – oraz pętlę for, która go napędza. Iteratory asynchroniczne dodają await do każdego kroku, dzięki czemu iterator może czekać pomiędzy wartościami bez blokowania pętli zdarzeń.

8.11.1. Protokół#

Klasa jest iteratorem asynchronicznym, gdy implementuje

  • __aiter__(self) – zwraca obiekt iteratora, zazwyczaj self.

  • async def __anext__(self) – zwraca następną wartość lub zgłasza StopAsyncIteration, gdy nie ma już więcej wartości.

Odpowiadającą jej konstrukcją pętli jest 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)

Pętla async for czeka (await) na każde wywołanie __anext__, więc korutyna napędzająca pętlę oddaje sterowanie pętli zdarzeń pomiędzy wartościami, dokładnie tak jak przy każdym innym await.

8.11.2. Kiedy z tego korzystać#

Zawsze, gdy aplikacja ma źródło danych napływających w czasie, a konsument powinien iterować po nich leniwie. Sensor produkujący próbkę na okres, gniazdo sieciowe dostarczające komunikaty, generator ramek – wszędzie tam, gdzie pasuje schemat while True: x = await source.next(); process(x), czystszym zapisem jest async for x in source.

Dla źródeł emitujących dane aż do skończonego warunku końcowego iterator zgłasza StopAsyncIteration, a async for kończy się normalnie. Dla źródeł, które nigdy się nie kończą – ciągłego strumienia z sensora, długotrwałej subskrypcji – pętla działa do momentu anulowania korutyny, w której się znajduje, lub zburzenia jej zadania.