Какие знаешь Dispatchers в Coroutines

Ответ

В Kotlin Coroutines есть несколько стандартных Dispatchers:

  1. Dispatchers.Main - для работы с UI (Android, JavaFX). Работает в главном потоке.
  2. Dispatchers.IO - для блокирующих операций (сеть, БД, файлы). Использует пул потоков.
  3. Dispatchers.Default - для CPU-интенсивных задач (сортировки, вычисления). Использует пул потоков размером с количество ядер CPU.
  4. Dispatchers.Unconfined - запускает корутину в текущем потоке, но после первой приостановки может продолжить в любом.

Пример:

viewModelScope.launch(Dispatchers.IO) {
    val data = fetchData() // IO операция
    withContext(Dispatchers.Main) {
        updateUI(data) // UI операция
    }
}

Ответ 18+ 🔞

А, слушай, про корутины и диспетчеры! Ну это ж классика, ебать мои старые костыли. Представь, что твоя корутина — это работяга, а диспетчер — это начальник цеха, который решает, на каком станке (то есть в каком потоке) этот работяга будет пахать.

Вот смотри, стандартных начальников-диспетчеров у нас несколько, и у каждого свой профиль, чтобы не было пиздеца.

  1. Dispatchers.Main — это, типа, главный прораб. Весь UI-шный движняк только через него. На Андроиде, в JavaFX — он рулит главным потоком. Попробуй из другого потока кнопку тронуть — получишь ёперный театр и краш приложения. Так что всё, что связано с отрисовкой, — строго к нему.
  2. Dispatchers.IO — это бригада грузчиков для тяжёлой работы. Сеть там, базы данных, файлы почитай-запиши — всё, что может надолго заблокировать поток. У него свой пул потоков, специально под такие дела заточенный. Жрёт их, как не в себя, когда задач много.
  3. Dispatchers.Default — это уже не грузчики, а инженеры-расчётчики. Для CPU-интенсивных дел: сортировки огромных списков, сложные вычисления, обработка изображений. Пул потоков у него обычно по размеру с количество ядер процессора, чтобы не мешать друг другу.
  4. Dispatchers.Unconfined — а это, бля, вольный художник или, как некоторые говорят, распиздяй. Запустится там, где его вызвали, а после первой же приостановки (suspend) может продолжить работу в совершенно любом другом потоке, куда его занесёт. Использовать его нужно с охуенно тонким пониманием, а то сам от себя охуеешь, где твой код выполняется.

Вот тебе живой пример, как это обычно выглядит в коде. Смотри, не трогай блок, он священный:

viewModelScope.launch(Dispatchers.IO) {
    val data = fetchData() // IO операция
    withContext(Dispatchers.Main) {
        updateUI(data) // UI операция
    }
}

Суть в чём? Всё начинаем в пуле для IO-операций (fetchData()), потому что там, скорее всего, сетевой запрос, который будет ждать ответа. А как только данные пришли, делаем хитрый манёвр — withContext(Dispatchers.Main) — и переключаемся в главный поток, чтобы безопасно обновить интерфейс (updateUI). Красота, а не жизнь! Главное — не перепутать, где считать, а где в сеть лезть, а то будет тебе хиросима вместо приложения.