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

Как работают корутины

2.0 Middle🔥 181 комментариев
#Многопоточность и асинхронность

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

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

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

Как работают корутины в Kotlin

Корутины — это один из самых мощных инструментов в Kotlin для асинхронного программирования. Это упрощение работы с асинхронным кодом по сравнению с callbacks и RxJava.

Что такое корутина?

Корутина — это функция, которая может быть приостановлена и возобновлена без блокировки потока. В отличие от потоков, корутины:

  • Легче по памяти (можно создать тысячи корутин вместо сотен потоков)
  • Не блокируют поток при ожидании результата
  • Легче управлять и отладить

Основные концепции

1. Suspend-функции

Suspend-функция — это функция, которая может быть приостановлена и возобновлена.

suspend fun fetchUser(id: String): User {
    // Эта функция может быть приостановлена
    return api.getUser(id)  // Сетевой запрос
}

Обычная функция не может вызвать suspend-функцию. Нужен контекст корутины:

viewModelScope.launch {
    val user = fetchUser("123")  // OK, мы внутри корутины
}

2. Dispatcher (Диспетчер)

Dispatcher определяет, на каком потоке будет выполняться корутина:

launch(Dispatchers.Main) {
    // Запустится на главном потоке UI
}

launch(Dispatchers.IO) {
    // Запустится на потоке для I/O операций (сеть, БД)
    val user = fetchUser("123")
}

launch(Dispatchers.Default) {
    // Запустится на фоновом потоке (CPU-bound операции)
    val result = heavyComputation()
}

Структурированность корутин

Важный принцип — корутины в Kotlin структурированы, т.е. дочерние корутины не могут жить дольше родительской.

viewModelScope.launch {  // Родительская корутина
    launch {  // Дочерняя корутина 1
        val user = fetchUser("123")
    }
    
    launch {  // Дочерняя корутина 2
        val posts = fetchPosts("123")
    }
    
    // Корутина viewModelScope не завершится, пока обе дочерние не завершатся
}

Это гарантирует, что:

  • Нет утечек памяти (дочерние корутины не висят в памяти)
  • При отмене родителя отменяются все дети
  • Исключения в дочерних корутинах пропагируются к родителю

Практический пример: загрузка пользователя

class UserViewModel(private val api: UserApi) : ViewModel() {
    private val _user = MutableLiveData<User>()
    val user: LiveData<User> = _user
    
    private val _error = MutableLiveData<String>()
    val error: LiveData<String> = _error
    
    fun loadUser(id: String) {
        viewModelScope.launch {
            try {
                val user = withContext(Dispatchers.IO) {
                    api.getUser(id)  // Запрос на IO потоке
                }
                _user.value = user  // Обновление на Main потоке
            } catch (e: Exception) {
                _error.value = e.message
            }
        }
    }
}

viewModelScope

viewModelScope — это встроенная CoroutineScope для ViewModel, которая:

  • Создаётся вместе с ViewModel
  • Отменяется при уничтожении ViewModel
  • Запускается на Dispatchers.Main.immediate по умолчанию

async/await для параллельных операций

Когда нужно выполнить несколько операций параллельно:

viewModelScope.launch {
    try {
        val userDeferred = async(Dispatchers.IO) { api.getUser("123") }
        val postsDeferred = async(Dispatchers.IO) { api.getPosts("123") }
        
        val user = userDeferred.await()  // Ждём результат
        val posts = postsDeferred.await()
        
        _data.value = Pair(user, posts)
    } catch (e: Exception) {
        _error.value = e.message
    }
}

Обработка исключений

viewModelScope.launch {
    try {
        val result = fetchData()
    } catch (e: CancellationException) {
        // Корутина была отменена (нормально)
        throw e  // Обязательно пробросить дальше
    } catch (e: Exception) {
        // Произошла ошибка
        _error.value = e.message
    }
}

Ключевые преимущества

  1. Простой синтаксис — код выглядит как синхронный
  2. Отмена операций — легко отменить все корутины при уничтожении View
  3. Управление ошибками — try/catch вместо сложных callback-цепочек
  4. Эффективность — тысячи корутин вместо потоков
  5. Интеграция — встроена в Jetpack компоненты (ViewModel, WorkManager и т.д.)
Как работают корутины | PrepBro