Гайды
Использование asyncio в Python
Event loop, Task и gather, таймауты и отмена, Lock и Semaphore, run_in_executor и отладка.
~10 мин чтения
Использование asyncio в Python
asyncio — стандартная библиотека кооперативной многозадачности в одном потоке (event loop): async/await, Tasks, синхронизация, стримы. В вебе это основа ASGI (FastAPI). Связка с API — Асинхронные эндпоинты и asyncpg; не путать с потоками Celery — Celery: очереди.
1. Корутина и цикл событий
import asyncio
async def main():
await asyncio.sleep(0.1)
return "done"
asyncio.run(main())
asyncio.run() — создаёт loop, запускает корутину, закрывает loop (точка входа в скриптах).
2. Task и gather
async def fetch(n: int) -> int:
await asyncio.sleep(0.05)
return n
async def main():
tasks = [asyncio.create_task(fetch(i)) for i in range(5)]
results = await asyncio.gather(*tasks)
return results
create_task — планирование; gather — параллельное ожидание (с return_exceptions=True при частичных ошибках).
3. Таймауты и отмена
async with asyncio.timeout(5):
await slow_call()
# или
task = asyncio.create_task(slow_call())
task.cancel()
try:
await task
except asyncio.CancelledError:
...
4. Синхронизация
Lock— взаимное исключение.Semaphore— ограничение параллелизма (например, не больше 10 одновременных HTTP-запросов).Queue— producer-consumer внутри процесса.
5. run_in_executor
Блокирующий код (CPU или старый sync I/O) не кладите в async def без изоляции:
loop = asyncio.get_running_loop()
await loop.run_in_executor(None, blocking_read_file, path)
6. Стримы: StreamReader/Writer
Низкоуровневые TCP/протоколы; для HTTP клиентов проще httpx.AsyncClient.
7. Отладка
asyncio.get_event_loop().set_debug(True)в dev — предупреждения о медленных колбэках.- Не смешивать разные loop в одном потоке.
asyncio.wait_for(coro, timeout) — оборачивает любую корутину дедлайном (удобнее, чем вручную create_task + cancel для простых случаев). Для совместимости с библиотеками вроде AnyIO (используется в Starlette/FastAPI) те же идеи таймаутов и отмены применимы к группам задач.
8. Чек-лист
- Нет скрытых
time.sleepв async-коде — толькоasyncio.sleep. - Ограничение параллелизма внешних API через Semaphore.
- Явные таймауты на сетевые вызовы.
- Тяжёлая CPU-работа — в процессах (
ProcessPoolExecutor), не в loop.
Дальше: WebSockets в FastAPI · тег Python