8.11. Asynchronní iterátory

Asynchronní iterátor je asyncio verzí iterátoru. Přehled jazyka Python představil synchronní protokol iterátoru – __iter__ a __next__ – a smyčku for, která jej řídí. Asynchronní iterátory přidávají do každého kroku await, takže iterátor může mezi hodnotami čekat, aniž by blokoval smyčku událostí.

8.11.1. Protokol

Třída je asynchronním iterátorem, pokud implementuje

  • __aiter__(self) – vrací objekt iterátoru, obvykle self.

  • async def __anext__(self) – vrací další hodnotu, nebo vyvolá StopAsyncIteration, když už žádné nezbývají.

Odpovídající konstrukcí smyčky je 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)

Smyčka async for čeká (await) na každé volání __anext__, takže korutina, která smyčku provádí, mezi hodnotami předává řízení smyčce událostí stejně jako u jakéhokoli jiného await.

8.11.2. Kdy po něm sáhnout

Vždy, když má aplikace zdroj dat, který přichází v průběhu času, a konzument jej má procházet líně. Senzor, který produkuje jeden vzorek za periodu, síťový soket doručující zprávy, generátor snímků – všude, kam se hodí tvar while True: x = await source.next(); process(x), je async for x in source čistším zápisem.

U zdrojů, které vysílají až do konečné koncové podmínky, iterátor vyvolá StopAsyncIteration a async for skončí běžným způsobem. U zdrojů, které nikdy nekončí – nepřetržitý proud ze senzoru, dlouhodobé odebírání – smyčka běží, dokud není zrušena korutina, ve které žije, nebo dokud není zlikvidována její úloha.