Короткий ответ
async и await применяются для неблокирующего кода там, где много ожидания: внешние API, файловые операции, сетевые запросы. Их не стоит использовать для вычислительных задач и простых программ без длительных ожиданий — выигрыша не будет.
Как это работает подробнее
В отличие от синхронного кода, где программа стоит на каждом ожидании, асинхронная программа работает в одном потоке и кооперативно переключает задачи в точках await.
- Кооперативность. Переключение происходит только в точках await, поэтому нет блокировок и гонок за общие данные, характерных для потоков.
- Масштаб. Один поток обслуживает тысячи одновременных соединений, пока корутины ждут внешние ресурсы.
- CPU-bound задачи. asyncio их не ускоряет: вычисления выполняются тем же процессором, поэтому нужны multiprocessing или потоки.
- Архитектура. Внутри обычной синхронной функции корутину не запустить: нужен await или asyncio.run(), поэтому асинхронность продумывают заранее.
Пример кода
Синхронное и асинхронное ожидание
# синхронное ожидание блокирует программу
import time
time.sleep(1)
# асинхронное ожидание позволяет выполнять другие задачи
import asyncio
async def task():
await asyncio.sleep(1)
return 'done'Что использовать на практике
- Выбор механизма. Для I/O-bound бери asyncio, для CPU-bound — multiprocessing или потоки.
- Простота. Не добавляй asyncio в программы без длительных ожиданий: лишняя сложность не окупается.
- Проектирование. Закладывай асинхронность с самого начала: перевести синхронную архитектуру потом трудно.