В какой последовательности выполняются корутины с Dispatchers.Main и Dispatchers.Default?
Что проверяют
Понимаете ли вы, что launch не выполняет код сразу, а отдаёт его диспетчеру, и чем постановка в очередь главного потока отличается от запуска на пуле. Обычно дают фрагмент с print в разных корутинах и просят назвать порядок вывода.
Как отвечать
Диспетчеры устроены по-разному:
Dispatchers.Main: на Android этоHandlerглавногоLooper.launch(Dispatchers.Main)кладёт задачу в очередь сообщений главного потока, даже если вы уже на нём. Код выполнится, когда закончится текущее сообщение, напримерonCreate;Dispatchers.Main.immediate: если вызов уже на главном потоке, корутина начинает выполняться сразу, до первой точки приостановки. Именно его используютlifecycleScopeиviewModelScopeпо умолчанию;Dispatchers.Default: пул для вычислений, потоков столько, сколько ядер, но не меньше двух. Корутина стартует на другом потоке параллельно, её порядок относительно главного потока не гарантирован.
Типичный пример внутри onCreate: print(1), затем lifecycleScope.launch(Dispatchers.Main) { print(2) }, затем lifecycleScope.launch(Dispatchers.Default) { print(3) }, затем print(4). Гарантировано: 1 раньше всего, 4 раньше 2. Тройка может появиться где угодно после единицы, даже до четвёрки. Если убрать явный Dispatchers.Main и оставить lifecycleScope.launch { }, сработает immediate, и 2 выведется сразу после 1.
Внутри одной корутины всё последовательно: withContext(Dispatchers.Default) { ... } приостанавливает её, главный поток свободен, а после завершения блока выполнение продолжается снова на Main.
Где спотыкаются
Считают, что код выполняется в порядке написания, и называют порядок 1, 2, 3, 4. Для обычного Main это неверно из-за постановки в очередь.
Отправляют сетевые запросы и работу с диском на Default. Для блокирующего ввода-вывода есть Dispatchers.IO с большим лимитом потоков, а Default рассчитан на задачи для CPU, и блокировка его потоков тормозит все вычисления в приложении.
Забывают, что в юнит-тестах на JVM Dispatchers.Main недоступен. Его подменяют через Dispatchers.setMain из kotlinx-coroutines-test.