Какие основные элементы и задачи содержит модуль asyncio в Python
Что проверяют
Понимаете ли вы кооперативную многозадачность: кто переключает корутины и почему одна блокирующая строка останавливает весь сервис. Следом обычно спрашивают, чем asyncio отличается от потоков и как выполнить несколько запросов одновременно.
Как отвечать
- цикл событий (event loop): планировщик в одном потоке. Выполняет готовые задачи, пока те не отдадут управление на
await, и следит за сокетами. Запускается черезasyncio.run(), с циклом вручную работают редко; - корутина: результат вызова
async def. Сам вызов ничего не выполняет, код пойдёт только приawaitили в составе задачи; - задача (
Task): корутина, поставленная в расписание черезasyncio.create_task(). Стартует, как только цикл получит управление; Future: низкоуровневый «результат будет позже», на нём построенTask. В прикладном коде встречается редко;- комбинаторы:
asyncio.gather()для одновременного ожидания,asyncio.TaskGroup(с 3.11), где ошибка одной задачи отменяет остальные,asyncio.timeout()иwait_for()для таймаутов; - синхронизация:
Lock,Semaphoreдля ограничения числа одновременных запросов,Event,asyncio.Queueдля схемы производитель и потребитель; - мост к блокирующему коду:
asyncio.to_thread()иloop.run_in_executor(); - ввод-вывод: streams (
open_connection,start_server) и подпроцессы (create_subprocess_exec).
Упомяните отмену: task.cancel() бросает CancelledError внутри корутины в точке await, и глотать это исключение нельзя.
Где спотыкаются
Вызывают в корутине time.sleep() или синхронный requests. Цикл встаёт целиком, и все остальные запросы ждут. Нужны asyncio.sleep() и асинхронные клиенты вроде httpx или aiohttp.
Запускают create_task и не сохраняют ссылку. Цикл держит задачи слабыми ссылками, незавершённую задачу может забрать сборщик мусора, а её исключение потеряется.
Считают, что asyncio ускоряет вычисления. Он выигрывает на ожидании сети и диска, а тяжёлую математику уносят в процессы: в стандартной сборке Python потоки упираются в GIL.