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

Какие знаешь типы корутин?

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

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

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

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

Типы корутин в Kotlin

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

1. По способу создания и запуска

launch-корутины

Это корутины, которые запускаются без явного возврата результата (возвращают Job). Используются для fire-and-forget задач.

scope.launch {
    // Выполнение фоновой задачи
    delay(1000)
    println("Завершено")
}

async-корутины

Корутины, возвращающие Deferred<T> (аналог Future/Promise), позволяющий получить результат позже через await().

val deferredResult = scope.async {
    delay(500)
    return@async 42
}

// В другом месте
val result = deferredResult.await()

produce-корутины (экспериментальные в kotlinx.coroutines)

Создают каналы (Channel) для потоковой передачи данных.

val channel = scope.produce {
    for (i in 1..5) {
        send(i * i)
    }
    close()
}

2. По области видимости (CoroutineScope)

Глобальные корутины (GlobalScope)

Запускаются в глобальной области видимости и живут всё время работы приложения. Не рекомендуются в Android из-за рисков утечек памяти.

GlobalScope.launch {
    // Работает пока не завершится или не будет отменена
}

Локальные скоупы (CoroutineScope)

Связаны с жизненным циклом компонентов (Activity, ViewModel, Fragment).

  • viewModelScope (в Android Architecture Components)
  • lifecycleScope (в Android Lifecycle)
  • Пользовательские скоупы с SupervisorJob и диспетчерами
class MyViewModel : ViewModel() {
    fun fetchData() {
        viewModelScope.launch {
            // Автоматически отменяется при очистке ViewModel
        }
    }
}

3. По контексту выполнения (CoroutineDispatcher)

Основной (UI) поток (Dispatchers.Main)

Для операций с UI в Android, Swing, JavaFX.

scope.launch(Dispatchers.Main) {
    updateUI()
}

Фоновые диспетчеры

  • Dispatchers.IO – для I/O операций (сеть, файлы, БД)
  • Dispatchers.Default – для CPU-интенсивных задач (сортировка, вычисления)
  • Dispatchers.Unconfined – не привязан к конкретному потоку (осторожно!)
scope.launch(Dispatchers.IO) {
    val data = fetchFromNetwork() // Блокирующий вызов
    withContext(Dispatchers.Main) {
        showData(data) // Возвращаемся в UI поток
    }
}

4. По особенностям поведения

Супервизорные корутины (SupervisorJob/supervisorScope)

Когда сбой в одной дочерней корутине не отменяет другие.

supervisorScope {
    launch { task1() } // Если упадёт,
    launch { task2() } // это продолжит работу
}

Структурированная параллельность

Иерархия корутин, где родитель управляет дочерними:

parentScope.launch {
    // Дочерние корутины
    launch { child1() }
    launch { child2() }
} // Все дочерние завершатся/отменятся при завершении родителя

Отменяемые vs неотменяемые

  • Отменяемые – стандартные корутины, поддерживающие cooperative cancellation
  • Неотменяемые – с использованием NonCancellable контекста
withContext(NonCancellable) {
    // Критическая операция, которая должна завершиться
    closeResources() // Даже при отмене корутины
}

5. По взаимодействию с потоками

Потокобезопасные корутины

Используют Mutex, Semaphore, атомарные переменные или withContext для безопасного доступа к общим ресурсам.

Актор-корутины (экспериментальные)

Реализуют паттерн Actor для обработки сообщений с гарантией последовательного выполнения.

val actor = scope.actor<Message> {
    for (msg in channel) {
        process(msg)
    }
}

Практическое значение

Различие типов корутин критически важно для:

  • Управления жизненным циклом в Android
  • Предотвращения утечек памяти
  • Оптимизации производительности (правильный выбор диспетчера)
  • Обработки ошибок (супервизор vs обычный job)
  • Тестирования (использование TestDispatcher)

Например, в Android приложении типичная структура выглядит так:

class Repository {
    suspend fun loadData(): Data = withContext(Dispatchers.IO) {
        // Сетевой запрос
    }
}

class MyViewModel : ViewModel() {
    fun load() {
        viewModelScope.launch {
            try {
                val data = repository.loadData()
                _state.value = Success(data)
            } catch (e: Exception) {
                _state.value = Error(e)
            }
        }
    }
}

Здесь сочетаются: viewModelScope (скоуп с жизненным циклом), launch-корутина для фоновой задачи, Dispatchers.IO для сетевого вызова, и структурированная отмена при очистке ViewModel.

Понимание этих типов позволяет строить отзывчивые, стабильные и эффективные асинхронные приложения, полностью используя преимущества корутин Kotlin.

Какие знаешь типы корутин? | PrepBro