← Назад к вопросам

В чем разница между основными CoroutineDispatcher?

1.8 Middle🔥 251 комментариев
#Kotlin основы#Архитектура и паттерны#Многопоточность и асинхронность

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Разница между основными CoroutineDispatcher

Dispatcher в Kotlin Coroutines определяет, в каком потоке или пуле потоков будет выполняться корутина. Это критический выбор для производительности и безопасности приложения.

Основные Dispatcher

1. Dispatchers.Main

Выполняет корутину в главном потоке UI:

launch(Dispatchers.Main) {
    // Выполняется в UI потоке
    button.text = "Clicked"  // Безопасно обновлять UI
}

Использование:

  • Обновление UI элементов
  • Работа с LiveData/StateFlow
  • Обработка событий

2. Dispatchers.IO

Оптимизирован для IO операций (сеть, файлы, БД):

launch(Dispatchers.IO) {
    // Выполняется в пуле потоков IO
    val data = database.getUser(id)  // Блокирующая операция
    val response = api.fetchData()   // Сетевой запрос
}

Использование:

  • Сетевые запросы (HTTP)
  • Операции с файлами
  • Работа с Room/SQLite
  • Работа с SharedPreferences

3. Dispatchers.Default

Для CPU-intensive операций:

launch(Dispatchers.Default) {
    // Выполняется в пуле потоков Default
    val result = heavyMathCalculation(bigList)
    val processed = parseJson(largeString)
}

Использование:

  • Сложные вычисления
  • Обработка больших объёмов данных
  • JSON парсинг
  • Сортировка, фильтрация больших коллекций

4. Dispatchers.Unconfined

Выполняется в текущем потоке без переключения:

launch(Dispatchers.Unconfined) {
    // Может выполняться в разных потоках
    // Использовать осторожно!
}

Использование:

  • Редко используется в production
  • Только для специфических case'ов
  • Тестирование

Сравнительная таблица

DispatcherТип потокаРазмер пулаИспользование
MainUI поток1UI, обновления
IOПул потоков64+ потоковСеть, файлы, БД
DefaultПул потоковCPU coresВычисления
UnconfinedТекущий-Редко

Правильное использование

Паттерн с withContext():

fun loadUserAndUpdateUI(userId: Int) {
    viewModelScope.launch(Dispatchers.Main) {
        // Начинаем в Main
        showLoading()  // Безопасно для UI
        
        // Переключаемся на IO
        val user = withContext(Dispatchers.IO) {
            database.getUser(userId)
        }
        
        // Возвращаемся в Main
        showUserData(user)  // Безопасно для UI
    }
}

Паттерн с async (параллельные операции):

suspend fun loadFullUserData(userId: Int) = withContext(Dispatchers.IO) {
    val profileAsync = async { api.getProfile(userId) }
    val settingsAsync = async { database.getSettings(userId) }
    val historyAsync = async { api.getHistory(userId) }
    
    UserData(
        profile = profileAsync.await(),
        settings = settingsAsync.await(),
        history = historyAsync.await()
    )
}

Common ошибки

1. Блокирующие операции в Dispatchers.Main

// НЕПРАВИЛЬНО
launch(Dispatchers.Main) {
    val data = database.getUser(id)  // Заморозит UI!
}

// ПРАВИЛЬНО
launch {
    val data = withContext(Dispatchers.IO) {
        database.getUser(id)
    }
}

2. IO операции в Dispatchers.Default

// НЕПРАВИЛЬНО
launch(Dispatchers.Default) {
    val response = api.fetchData()  // Пусто потоки Default
}

// ПРАВИЛЬНО
launch(Dispatchers.IO) {
    val response = api.fetchData()
}

3. Забыли указать Dispatcher

// viewModelScope.launch по умолчанию использует Main + IO
viewModelScope.launch {  // Неявно Main.immediate
    val data = withContext(Dispatchers.IO) {
        heavyWork()
    }
}

Best Practices

  • Используй viewModelScope для UI обновлений — автоматически в Main
  • Используй Dispatchers.IO для сети/БД — специализированный пул
  • Используй Dispatchers.Default для вычислений — оптимизирован для CPU
  • Избегай Dispatchers.Unconfined — может привести к неожиданному поведению
  • Явно указывай withContext() — вносит ясность в код

Правильный выбор Dispatcher — это ключ к производительному и отзывчивому Android приложению.