Асинхронные контекстные менеджеры, итераторы и связь sync/async кода

Тема дорожной карты · Python Programming

Асинхронные контекстные менеджеры и итераторы являются ключевыми элементами при работе с асинхронным кодом в Python. Они позволяют эффективно управлять ресурсами и выполнять операции I/O без блокировки выполнения программы. Важность этих механизмов заключается в том, что они помогают создавать масштабируемые и производительные приложения, особенно когда речь идет о работе с сетью и базами данных.

async with и async for расширяют знакомый протокол на ресурсы, дружащие с корутинами — асинхронные сессии БД, HTTP-клиенты, потребители очередей. Сложная часть — это interop: никогда не вызывай блокирующий I/O внутри корутины (это замораживает весь event loop) и никогда не вызывай корутины из sync-кода без работающего event loop. Связывай их через asyncio.to_thread, loop.run_in_executor или anyio.from_thread. Trio и anyio подталкивают к structured concurrency через nursery.

Как это работает

Асинхронные контекстные менеджеры, итераторы и связь sync/async кода используют asyncio (с Yöntem: asyncio (с Python 3.4) — однопоточный event loop, исполняющий корутины (функции async def). Команда await приостанавливает корутину до завершения awaitable; loop тем временем переключается на другую готовую. Задачи (asyncio.create_task) гоняют корутины конкурентно; asyncio.gather(*tasks) ждёт многих параллельно. Async-библиотеки (aiohttp, asyncpg, httpx) заменяют блокирующие. Sync-код блокирует loop — никогда не зовите time.sleep или requests.get внутри async def.

Когда применять

Асинхронные контекстные менеджеры и итераторы полезны, когда нагрузка I/O-bound и конкурентная — тысячи HTTP-запросов, WebSocket fan-out, скрейпинг, асинхронный доступ к БД во веб-фреймворке (FastAPI). Для CPU-bound задач асинхронное программирование не помогает — лучше использовать multiprocessing или внешних воркеров. Для простых линейных скриптов с парой HTTP-вызовов синхронный requests короче и проще для отладки; асинхронное программирование окупается при ~50+ конкурентных операциях.

Типичные ошибки

Типичные ошибки при работе с асинхронными контекстными менеджерами и итераторами включают смешение sync-блокирующих вызовов в async-коде (один time.sleep(1) замораживает весь event loop); запуск неограниченных задач без обратной связи (память взрывается); забытый await — получите coroutine-объект, который никогда не запустится (Python 3.11+ предупреждает); неосторожное смешивание потоков + asyncio (asyncio.run_in_executor существует для блокирующих вызовов — используйте). Для отладки используйте PYTHONASYNCIODEBUG=1 и asyncio.Task.get_stack().

Связанные понятия

Полезные ресурсы