Менеджер контекста Async — это объект, который определяет асинхронные методы __aenter__ и __aexit__ и используется в конструкции async with. Такой менеджер нужен для корректного открытия/закрытия ресурсов в асинхронных функциях: соединений с БД, файлов, сессий и т.д.
Пример реализации:
class AsyncDBConnection: async def __aenter__(self): self.conn = await async_db_connect() return self.conn async def __aexit__(self, exc_type, exc, tb): await self.conn.close() async def main(): async with AsyncDBConnection() as conn: await conn.query('SELECT 1')
Асинхронный контекст позволяет не блокировать event loop техническими задержками, повышая производительность concurrent-программ.
Можно ли использовать обычный with внутри async def?
Ответ: Да, но если операции внутри менеджера контекста используют awaitable (требуют await), нужен именно async with. Обычный with не поддерживает асинхронный enter/exit, будет блокировать event loop/ или упадёт, если вызвать await внутри enter/exit.
Пример:
async def foo(): with open('file.txt') as f: # это ок, чтение синхронное data = f.read() # Но нельзя await внутри обычного контекста, только внутри async with
История
Проект: Веб-сервис с асинхронным API.
Проблема: Менеджер подключения к базе использовал обычный with, но внутри был вызван await. Это привело к ошибке RuntimeError("Cannot use 'await' outside async function") и блокировкам event loop в проде.
История
Проект: Чат на Websockets.
Проблема: При работе с соединениями не закрывались websocket-ресурсы (использовали обычный синхронный менеджер), что приводило к утечкам памяти и зависшим соединениям.
История
Проект: Многопоточная асинхронная очередь заданий.
Проблема: Менеджер задач некорректно реализовал
__aexit__, забыли возвращать awaitable. Из-за этого завершение задач происходило не гарантировано, и часть заданий "зависала" в системе.