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, vanligtvisself.async def __anext__(self)– returnerar nästa värde, eller höjerStopAsyncIterationnä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.