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.