8.11. 非同步迭代器¶
非同步迭代器(async iterator)是迭代器的 asyncio 版本。Python 概觀 介紹過同步的迭代器協定 -- __iter__ 與 __next__ -- 以及驅動它的 for 迴圈。非同步迭代器為每個步驟加上一個 await,因此迭代器可以在產生值之間等待,而不會阻塞事件迴圈。
8.11.1. 協定¶
當一個類別實作了下列方法時,它就是非同步迭代器
__aiter__(self)-- 回傳迭代器物件,通常是self。async def __anext__(self)-- 回傳下一個值,或在沒有更多值時引發StopAsyncIteration。
對應的迴圈結構是 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 迴圈會 await 每次對 __anext__ 的呼叫,因此執行該迴圈的協程會在產生值之間將控制權交還給事件迴圈,就和任何其他 await 一樣。
8.11.2. 何時該使用它¶
只要應用程式有一個隨時間陸續到達的資料來源,而消費端應該以惰性方式迭代它時,就適合使用。每隔一段時間產生一筆樣本的感測器、傳遞訊息的網路 socket、影格產生器 -- 任何符合 while True: x = await source.next(); process(x) 形式的地方,async for x in source 都是更俐落的寫法。
對於會持續發出值直到某個有限結束條件的來源,迭代器會引發 StopAsyncIteration,而 async for 會正常結束。對於永不結束的來源 -- 持續不斷的感測器串流、長時間執行的訂閱 -- 迴圈會一直執行,直到它所在的協程被取消或其任務被拆除為止。