8.11. Iteradores assíncronos¶
Um iterador assíncrono é a versão asyncio de um iterador. A Visão Geral do Python apresentou o protocolo de iterador síncrono – __iter__ e __next__ – e o ciclo for que o acciona. Os iteradores assíncronos adicionam um await a cada passo, para que o iterador possa esperar entre valores sem bloquear o event loop.
8.11.1. O protocolo¶
Uma classe é um iterador assíncrono quando implementa
__aiter__(self)– devolve o objeto iterador, normalmenteself.async def __anext__(self)– devolve o próximo valor, ou lançaStopAsyncIterationquando não há mais.
O construtor de ciclo correspondente é 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)
O ciclo async for aguarda cada chamada a __anext__, pelo que a coroutine que executa o ciclo cede o controlo ao event loop entre valores, tal como qualquer outro await.
8.11.2. Quando usar¶
Sempre que a aplicação tem uma fonte de dados que chega ao longo do tempo e o consumidor deve iterá-la de forma preguiçosa. Um sensor que produz uma amostra por período, um socket de rede que entrega mensagens, um gerador de fotogramas – em qualquer lugar onde o padrão while True: x = await source.next(); process(x) se aplique, async for x in source é a forma mais limpa.
Para fontes que emitem até uma condição de fim finita, o iterador lança StopAsyncIteration e async for termina normalmente. Para fontes que nunca terminam – um fluxo contínuo de sensor, uma subscrição de longa duração – o ciclo executa até que a coroutine em que reside seja cancelada ou a sua tarefa seja destruída.