8.11. Async iterators¶
async iterator คือเวอร์ชัน asyncio ของ iterator Python Overview ได้แนะนำโปรโตคอล iterator แบบ synchronous -- __iter__ และ __next__ -- และลูป for ที่ขับเคลื่อนมัน Async iterators เพิ่ม await ให้กับแต่ละขั้นตอน ดังนั้น iterator สามารถ รอ ระหว่างค่าต่างๆ โดยไม่บล็อก event loop
8.11.1. โปรโตคอล¶
class เป็น async iterator เมื่อมันใช้งาน
__aiter__(self)-- คืนอ็อบเจกต์ iterator มักเป็นselfasync 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__ แต่ละครั้ง ดังนั้น coroutine ที่รันลูปจะยึดควบคุมให้กับ event loop ระหว่างค่าต่างๆ เหมือนกับ await อื่นๆ
8.11.2. เมื่อไรควรใช้¶
เมื่อแอปพลิเคชันมีแหล่งข้อมูลที่มาถึง ตามเวลา และผู้ใช้ควรวนซ้ำแบบ lazy เซนเซอร์ที่ผลิตตัวอย่างต่อช่วงเวลา socket เครือข่ายที่ส่งข้อความ frame generator -- ที่ใดก็ตามที่รูปแบบ while True: x = await source.next(); process(x) เหมาะ async for x in source เป็นวิธีเขียนที่สะอาดกว่า
สำหรับแหล่งข้อมูลที่ส่งออกจนถึงเงื่อนไขสิ้นสุดที่แน่นอน iterator จะยก StopAsyncIteration และ async for จะออกปกติ สำหรับแหล่งข้อมูลที่ไม่มีที่สิ้นสุด -- กระแส sensor ต่อเนื่อง การ subscribe แบบรันนาน -- ลูปจะทำงานจนกว่า coroutine ที่มันอยู่จะถูกยกเลิกหรือ task ของมันถูกทำลาย