Какие задачи подходят для асинхронного выполнения, а какие нет?
Что проверяют
Понимаете ли вы, что выигрыш даёт только ожидание, и знаете ли, что делать с неподходящими задачами.
Как отвечать
Критерий один: на что уходит время. Если задача в основном ждёт внешнего события, асинхронность даёт выигрыш, пропорциональный числу одновременных операций. Если задача считает, выигрыша нет вовсе, потому что цикл событий работает в одном потоке.
Подходят:
- сетевые запросы к API и между сервисами;
- работа с базой через асинхронный драйвер;
- обслуживание множества одновременных соединений: веб-сервер, вебсокеты, длинные опросы;
- чтение из очереди сообщений;
- любые операции, где программа простаивает в ожидании ответа.
Не подходят:
- вычисления: обработка изображений, разбор большого объёма данных, применение модели, криптография. Такой код блокирует весь цикл, и все остальные корутины стоят;
- вызовы синхронных библиотек. Обычный клиент HTTP, синхронный драйвер базы или пауза из стандартного модуля времени останавливают всё приложение, даже будучи вызванными внутри корутины;
- работа с локальными файлами. В стандартном цикле событий настоящей асинхронности для файлов нет, операции всё равно выполняются в пуле потоков.
Что делать с неподходящими, а не просто отказываться:
- блокирующий вызов уводят в поток отдельной функцией переноса, и цикл остаётся свободным;
- вычисления уносят в пул процессов, потому что потоки из-за глобальной блокировки не помогут;
- тяжёлые библиотеки на C вроде численных пакетов сами отпускают блокировку, и с ними ситуация лучше.
Практический признак ошибки в проде: время ответа растёт у всех запросов сразу, а не у одного. Это почти всегда означает, что кто-то заблокировал цикл событий.
Где спотыкаются
Ждут ускорения вычислений от асинхронности.
Вызывают синхронную библиотеку внутри корутины.
Считают, что работа с файлами асинхронна.
Не выносят блокирующий код в поток и подвешивают весь сервис.