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.