8.11. Iteratori asincroni¶
Un iterator asincron este versiunea asyncio a unui iterator. Prezentarea generală Python a introdus protocolul iteratorului sincron – __iter__ și __next__ – și bucla for care îl pune în mișcare. Iteratorii asincroni adaugă un await la fiecare pas, astfel încât iteratorul poate aștepta între valori fără a bloca bucla de evenimente.
8.11.1. Protocolul¶
O clasă este un iterator asincron atunci când implementează
__aiter__(self)– returnează obiectul iterator, de obiceiself.async def __anext__(self)– returnează valoarea următoare sau ridicăStopAsyncIterationatunci când nu mai există valori.
Construcția de buclă corespunzătoare este 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)
Bucla async for așteaptă fiecare apel către __anext__, astfel încât corutina care execută bucla cedează controlul buclei de evenimente între valori, exact ca orice alt await.
8.11.2. Când să apelezi la el¶
Ori de câte ori aplicația are o sursă de date care sosesc în timp și consumatorul ar trebui să le itereze în mod leneș. Un senzor care produce o eșantionare pe perioadă, un socket de rețea care livrează mesaje, un generator de cadre – oriunde se potrivește forma while True: x = await source.next(); process(x), async for x in source este formularea mai curată.
Pentru surse care emit până la o condiție de încheiere finită, iteratorul ridică StopAsyncIteration și async for se încheie normal. Pentru surse care nu se termină niciodată – un flux continuu de la un senzor, un abonament de lungă durată – bucla rulează până când corutina în care se află este anulată sau sarcina sa este desființată.