Что происходит при выполнении тяжелой процессорной операции в синхронной задаче?
Что проверяют
Понимаете ли вы, что асинхронность в Python не даёт параллелизма, и знаете ли, куда выносить счёт. Вопрос обычно про корутину, внутри которой оказался синхронный тяжёлый вызов.
Как отвечать
Цикл событий asyncio крутится в одном потоке. Переключение между корутинами возможно только на await, то есть там, где корутина сама отдаёт управление. Чистый счёт таких точек не содержит, поэтому на всё время его работы цикл стоит: другие корутины не выполняются, принятые соединения не обслуживаются, таймеры срабатывают с опозданием, сигнал живости брокеру не уходит. Снаружи это выглядит не как один медленный запрос, а как зависший сервис, потому что встают сразу все.
Куда переносить, зависит от природы работы:
- счёт на чистом Python: отдельный процесс,
ProcessPoolExecutorчерезloop.run_in_executor, отдельный воркер очереди задач; - библиотека, которая внутри отпускает блокировку интерпретатора (
numpy, сжатие, хеширование, парсеры на C): достаточно потока,asyncio.to_thread; - ввод-вывод, случайно вызванный синхронно (
requests,time.sleep, синхронный драйвер базы): заменить на асинхронный аналог.
Сильный ответ добавляет, что проблема диагностируется, а не ищется глазами: у цикла событий есть режим отладки, который пишет предупреждение о колбэке, занявшем слишком долго.
Где спотыкаются
Предлагают потоки для ускорения счёта. Глобальная блокировка интерпретатора пускает в байт-код один поток за раз, поэтому чистый Python в потоках не ускорится, а на переключениях станет медленнее. Сборка интерпретатора без этой блокировки существует, но это отдельная сборка, а не поведение по умолчанию.
Второе: говорят, что asyncio выполнит тяжёлую операцию в фоне. Фона там нет, корутина работает в том же потоке, и слово async перед функцией ничего не ускоряет.
Третье: описывают последствия словами про зависший интерфейс, взятыми из мира приложений с окном. У сервиса признаки другие: растущая задержка на всех ручках, отваливающиеся по таймауту проверки живости и перезапуск оркестратором.