8.11. Asynkroniset iteraattorit¶
Asynkroninen iteraattori on iteraattorin asyncio-versio. Python-yleiskatsaus esitteli synkronisen iteraattoriprotokollan – __iter__ ja __next__ – sekä sitä ohjaavan for-silmukan. Asynkroniset iteraattorit lisäävät jokaiseen vaiheeseen await-lauseen, joten iteraattori voi odottaa arvojen välillä estämättä tapahtumasilmukkaa.
8.11.1. Protokolla¶
Luokka on asynkroninen iteraattori, kun se toteuttaa
__aiter__(self)– palauttaa iteraattoriobjektin, yleensäself.async def __anext__(self)– palauttaa seuraavan arvon tai nostaaStopAsyncIteration, kun arvoja ei ole enää jäljellä.
Vastaava silmukkarakenne on 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 -silmukka odottaa jokaista __anext__ -kutsua, joten silmukkaa suorittava korutiini luovuttaa vuoron tapahtumasilmukalle arvojen välillä aivan kuten mikä tahansa muu await.
8.11.2. Milloin sitä kannattaa käyttää¶
Aina kun sovelluksella on tietolähde, joka saapuu ajan myötä ja jota kuluttajan tulisi iteroida laiskasti. Sensori, joka tuottaa näytteen jaksoa kohden, verkkosoketti, joka toimittaa viestejä, kehysgeneraattori – kaikkialla, missä muoto while True: x = await source.next(); process(x) sopii, async for x in source on siistimpi ilmaisutapa.
Lähteille, jotka tuottavat dataa äärelliseen loppuehtoon asti, iteraattori nostaa StopAsyncIteration ja async for poistuu normaalisti. Lähteille, jotka eivät koskaan pääty – jatkuva sensorivirta, pitkäkestoinen tilaus – silmukka jatkuu, kunnes korutiini, jossa se elää, perutaan tai sen tehtävä puretaan.