8.11. Asynkrona iteratorer

En asynkron iterator är asyncio-versionen av en iterator. Python-översikten introducerade det synkrona iteratorprotokollet – __iter__ och __next__ – samt for-loopen som driver det. Asynkrona iteratorer lägger till ett await i varje steg, så att iteratorn kan vänta mellan värdena utan att blockera händelseloopen.

8.11.1. Protokollet

En klass är en asynkron iterator när den implementerar

  • __aiter__(self) – returnerar iteratorobjektet, vanligtvis self.

  • async def __anext__(self) – returnerar nästa värde, eller höjer StopAsyncIteration när det inte finns några fler.

Motsvarande loopkonstruktion är 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-loopen inväntar varje anrop till __anext__, så att den coroutine som kör loopen lämnar över till händelseloopen mellan värdena precis som vilket annat await som helst.

8.11.2. När den ska användas

När applikationen har en datakälla som anländer över tid och konsumenten bör iterera den lat. En sensor som producerar ett sampel per period, ett nätverkssocket som levererar meddelanden, en bildrutegenerator – överallt där formen while True: x = await source.next(); process(x) passar är async for x in source det renare uttrycket.

För källor som sänder fram till ett ändligt slutvillkor höjer iteratorn StopAsyncIteration och async for avslutas normalt. För källor som aldrig tar slut – en kontinuerlig sensorström, en långvarig prenumeration – körs loopen tills den coroutine den lever i avbryts eller dess uppgift rivs ned.