Introduction
Async generators combine async functions with generator capabilities, allowing iteration over asynchronous data sources with async for.
Basic Async Generator
async def async_range(start, stop):
for i in range(start, stop):
await asyncio.sleep(0.1) # Simulate async operation
yield i
async def main():
async for num in async_range(0, 5):
print(f"Got: {num}")
asyncio.run(main())
Async Generator Pipeline
async def produce():
for i in range(10):
await asyncio.sleep(0.1)
yield i
async def transform(item):
await asyncio.sleep(0.1)
return item * 2
async def consume():
async for item in produce():
result = await transform(item)
print(f"Processed: {result}")
asyncio.run(consume())
Async Iterator Protocol
class AsyncCounter:
def __init__(self, limit):
self.limit = limit
self.current = 0
def __aiter__(self):
return self
async def __anext__(self):
if self.current >= self.limit:
raise StopAsyncIteration
value = self.current
self.current += 1
await asyncio.sleep(0.1)
return value
async def main():
async for i in AsyncCounter(5):
print(i)
asyncio.run(main())
aclose and athrow
async def async_gen():
try:
for i in range(10):
yield i
except asyncio.CancelledError:
print("Generator cancelled")
raise
async def main():
ag = async_gen()
async for i in ag:
print(i)
if i == 5:
await ag.aclose()
asyncio.run(main())
Async Generator with send
async def async_gen_with_send():
value = None
while True:
received = yield value
value = received * 2 if received else 0
async def main():
gen = async_gen_with_send()
await gen.asend(None) # Prime
print(await gen.asend(5)) # 10
print(await gen.asend(3)) # 6
asyncio.run(main())
Practice Problems
- Create async generator for streaming data
- Build async generator pipeline
- Implement async iterator class
- Handle cancellation properly
- Use asend with async generators