Async Context Managers and Async Generators
Async context managers (async withasync with)
You use async withasync with when acquiring/releasing a resource needs awaitawait.
Common examples:
aiohttp.ClientSession()aiohttp.ClientSession()- async database connections
- async locks (
asyncio.Lockasyncio.Lock)
Example: sessions and responses
aiohttp_context_manager.py
import asyncio
import aiohttp
async def main():
async with aiohttp.ClientSession() as session:
async with session.get("https://api.github.com") as resp:
data = await resp.json()
print(resp.status)
print("keys:", list(data.keys())[:5])
asyncio.run(main())aiohttp_context_manager.py
import asyncio
import aiohttp
async def main():
async with aiohttp.ClientSession() as session:
async with session.get("https://api.github.com") as resp:
data = await resp.json()
print(resp.status)
print("keys:", list(data.keys())[:5])
asyncio.run(main())Writing your own async context manager
Use @asynccontextmanager@asynccontextmanager for a clean pattern.
custom_async_context_manager.py
import asyncio
from contextlib import asynccontextmanager
@asynccontextmanager
async def managed_resource(name: str):
print("acquire", name)
await asyncio.sleep(0.1)
try:
yield {"name": name}
finally:
print("release", name)
await asyncio.sleep(0.1)
async def main():
async with managed_resource("db-conn") as res:
print(res)
asyncio.run(main())custom_async_context_manager.py
import asyncio
from contextlib import asynccontextmanager
@asynccontextmanager
async def managed_resource(name: str):
print("acquire", name)
await asyncio.sleep(0.1)
try:
yield {"name": name}
finally:
print("release", name)
await asyncio.sleep(0.1)
async def main():
async with managed_resource("db-conn") as res:
print(res)
asyncio.run(main())Async generators (async defasync def + yieldyield)
An async generator is a generator that can awaitawait between yields.
Itβs perfect for streaming data without loading everything into memory.
Example: async generator + async forasync for
async_generator.py
import asyncio
async def ticker(n: int, delay: float = 0.2):
for i in range(n):
await asyncio.sleep(delay)
yield i
async def main():
async for value in ticker(5):
print(value)
asyncio.run(main())async_generator.py
import asyncio
async def ticker(n: int, delay: float = 0.2):
for i in range(n):
await asyncio.sleep(delay)
yield i
async def main():
async for value in ticker(5):
print(value)
asyncio.run(main())Important gotchas
- Use
async withasync withonly with objects that implement__aenter____aenter__/__aexit____aexit__. - Use
async forasync foronly on async iterables (implement__aiter____aiter__). - Donβt forget to close async resources (sessions, connections).
async withasync withhelps you avoid leaks.
π§ͺ Try It Yourself
Exercise 1 β Your First Coroutine
Exercise 2 β await asyncio.sleep
Exercise 3 β Gather Two Coroutines
If this helped you, consider buying me a coffee β
Buy me a coffeeWas this page helpful?
Let us know how we did
