Как работает asyncio в Python?
Что проверяют
Понимаете ли вы, что это кооперативная многозадачность в одном потоке, и знаете ли, что её ломает.
Как отвечать
asyncio это цикл событий, выполняющий корутины в одном потоке. Корутина работает, пока не дойдёт до await над операцией ожидания: там она отдаёт управление циклу, и он берёт следующую готовую задачу. Когда результат приходит, выполнение продолжается с той же точки.
Ключевые понятия: корутина (объект от вызова async def), задача (asyncio.create_task, корутина, поставленная в цикл), await (точка приостановки), gather и TaskGroup для параллельного ожидания нескольких операций.
async def main():
async with asyncio.TaskGroup() as tg:
tg.create_task(fetch(url1))
tg.create_task(fetch(url2)) # оба запроса идут одновременно
asyncio.run(main())Что важно понимать про границы:
- потоков не создаётся и GIL не обходится: выигрыш только на ожидании сети и диска, на вычислениях его нет;
- любой блокирующий вызов останавливает весь цикл, включая все остальные задачи.
time.sleep,requests, синхронный драйвер базы, тяжёлый расчёт. Такое выносят вrun_in_executorили берут асинхронные библиотеки (httpx,asyncpg); - задачу нужно сохранять: ссылку на
create_taskдержат, иначе сборщик мусора может её убрать; - отмена кооперативная:
task.cancel()бросает исключение в точке приостановки, и его нельзя молча глотать.
Где спотыкаются
Считают, что asyncio даёт параллелизм.
Зовут time.sleep вместо asyncio.sleep.
Пишут последовательные await там, где нужен gather.
Используют синхронный клиент базы внутри асинхронного кода.