8.11. Asynchrone Iteratoren¶
Ein asynchroner Iterator ist die asyncio-Variante eines Iterators. Die Python-Übersicht hat das synchrone Iterator-Protokoll eingeführt – __iter__ und __next__ – sowie die for-Schleife, die es antreibt. Asynchrone Iteratoren fügen jedem Schritt ein await hinzu, sodass der Iterator zwischen den Werten warten kann, ohne die Ereignisschleife zu blockieren.
8.11.1. Das Protokoll¶
Eine Klasse ist ein asynchroner Iterator, wenn sie Folgendes implementiert
__aiter__(self)– gibt das Iterator-Objekt zurück, normalerweiseself.async def __anext__(self)– gibt den nächsten Wert zurück oder löstStopAsyncIterationaus, wenn keine weiteren Werte vorhanden sind.
Das zugehörige Schleifenkonstrukt ist 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)
Die async for-Schleife erwartet jeden Aufruf von __anext__, sodass die Koroutine, die die Schleife ausführt, zwischen den Werten die Kontrolle an die Ereignisschleife abgibt – genau wie bei jedem anderen await.
8.11.2. Wann man darauf zurückgreift¶
Immer dann, wenn die Anwendung eine Datenquelle hat, deren Daten im Laufe der Zeit eintreffen und vom Konsumenten verzögert (lazy) iteriert werden sollen. Ein Sensor, der pro Periode eine Probe liefert, ein Netzwerk-Socket, der Nachrichten zustellt, ein Einzelbild-Generator – überall dort, wo die Form while True: x = await source.next(); process(x) passt, ist async for x in source die elegantere Schreibweise.
Bei Quellen, die bis zu einer endlichen Abbruchbedingung Werte liefern, löst der Iterator StopAsyncIteration aus und async for wird normal beendet. Bei Quellen, die nie enden – ein kontinuierlicher Sensorstrom, ein langlaufendes Abonnement – läuft die Schleife so lange, bis die Koroutine, in der sie lebt, abgebrochen oder ihr Task abgebaut wird.