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 nostaa StopAsyncIteration, 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.