Какие диспетчеры бывают в Kotlin Coroutines
Что проверяют
Знаете ли вы четыре стандартных диспетчера и понимаете ли, чем IO отличается от Default. На этом чаще всего и ошибаются.
Как отвечать
Диспетчер решает, на каком потоке выполняется корутина.
- Dispatchers.Main: главный поток. Всё, что трогает интерфейс. В Android это поток UI, вариант
Main.immediateне переключает контекст, если он уже главный; - Dispatchers.Default: пул размером по числу ядер (минимум два). Для вычислений: разбор, сортировка, обработка данных;
- Dispatchers.IO: пул до 64 потоков, рассчитан на блокирующие операции. Сеть, файлы, синхронные драйверы базы. Потоки делит с
Default, но лимит у него свой; - Dispatchers.Unconfined: выполняется на вызывающем потоке до первой приостановки, дальше на том, где продолжится. В обычном коде не нужен, используется в тестах и в редких оптимизациях.
Ключевое отличие IO от Default в том, что первый допускает блокировку потока, а второй нет. Тяжёлый расчёт на IO займёт поток, предназначенный для ожидания; блокирующий вызов на Default съест ядро из маленького пула и подвесит остальные вычисления.
Переключение делается через withContext(Dispatchers.IO) { ... }, причём в корутинах принято, чтобы приостанавливаемая функция сама выбирала свой диспетчер, а вызывающий об этом не думал.
Для тестов есть StandardTestDispatcher и UnconfinedTestDispatcher вместе с runTest, они делают выполнение предсказуемым.
Где спотыкаются
Считают IO бесконечным и запускают на нём сотни блокирующих задач.
Делают тяжёлый расчёт на IO, а блокирующий вызов на Default.
Обновляют интерфейс не с Main и получают падение.
Заставляют вызывающего оборачивать вызовы в withContext вместо того, чтобы сделать это внутри функции.