launch — суть, fire-and-forget запуск сопрограмм и как работает

Автор: IT Sectr Опубликовано: 2026-06-22 Время чтения: 7 мин

launch — Coroutine Builder в Kotlin, который запускает сопрограмму без возврата результата, возвращая объект Job для управления выполнением. Этот билдер реализует паттерн fire-and-forget: корутина начинает работу в фоновом потоке и автоматически завершается. По данным документации JetBrains, 2024, launch является основным способом запуска параллельных задач в Kotlin Coroutines.

Главное

  • launch — билдер для запуска сопрограмм без возврата результата (fire-and-forget)
  • Job — объект управления корутиной с методами cancel(), join(), isActive
  • launch интегрируется с CoroutineScope для автоматической отмены дочерних корутин
  • CoroutineStart.LAZY позволяет отложить запуск до явного вызова start() или join()
  • launch в Android используется для сохранения в БД, сетевых вызовов и обновления UI

Что такое launch в Kotlin Coroutines?

launch — это функция-расширение Kotlin, доступная через импорт kotlinx.coroutines, которая создаёт новую сопрограмму в заданном CoroutineScope. В отличие от обычных функций, код внутри launch выполняется конкурентно — корутина может приостанавливаться (suspend) без блокировки потока и возобновляться позже.

Билдер launch является фундаментальным строительным блоком корутинной модели Kotlin. Он не возвращает вычисленное значение, но возвращает объект Job, позволяющий контролировать выполнение корутины. Все дочерние корутины, запущенные через launch внутри другой корутины, привязываются к родительской.

Синтаксис и параметры launch

Билдер launch определяется как inline-функция с несколькими параметрами: CoroutineScope, CoroutineContext, CoroutineStart и suspend-блок. Параметры имеют значения по умолчанию, что делает launch удобным для типовых сценариев.

kotlin
public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job

Параметр context принимает CoroutineContext, объединяющий диспетчер, обработчик исключений и именованный элемент. Чаще всего передаётся Dispatchers.IO, Dispatchers.Main или SupervisorJob для изоляции ошибок.

Job и управление жизненным циклом

Job — возвращаемый объект, представляющий жизненный цикл корутины. Job может находиться в состояниях: New, Active, Completing, Completed, Cancelling, Cancelled. Каждое состояние отражает статус выполнения и позволяет реагировать на изменения.

kotlin
val job = CoroutineScope(Dispatchers.IO).launch {
    repeat(10) { i ->
        delay(1000L)
        println("Progress: $i")
    }
}

println("Job is active: ${job.isActive}")
delay(2500L)
job.cancel()
println("Job is cancelled: ${job.isCancelled}")

Job поддерживает иерархию: если родительская корутина отменяется, все дочерние автоматически отменяются. SupervisorJob изменяет это поведение — дочерние корутины не отменяются при ошибке одной из них.

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

Структурированная конкурентность означает, что каждая корутина запускается в определённом CoroutineScope, и scope не завершится, пока все дочерние корутины не закончат работу. launch полностью поддерживает этот принцип — корутины, запущенные внутри другой корутины, являются её дочерними.

Вложенные launch вызовы

При вложенном запуске launch образуется дерево корутин. Родительская корутина ожидает завершения всех дочерних, что гарантирует предсказуемый порядок выполнения и упрощает управление ресурсами.

kotlin
fun main() = runBlocking {
    launch {
        launch {
            delay(1000L)
            println("Child 1 completed")
        }
        launch {
            delay(500L)
            println("Child 2 completed")
        }
        println("All children complete before this line")
    }
}

Это поведение отличается от thread-based конкурентности, где дочерние потоки не привязаны к родительскому. В корутинах родитель не завершится, пока все дети не закончат работу.

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

Обработка исключений в launch зависит от типа Job. Для обычного Job исключения распространяются на родительскую корутину и отменяют её. Для SupervisorJob или SupervisorScope исключения изолируются — ошибка одной дочерней корутины не затрагивает другие.

kotlin
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
    try {
        riskyOperation()
    } catch (e: Exception) {
        println("Caught: ${e.message}")
    }
}
scope.launch {
    println("This still runs thanks to SupervisorJob")
}

Для глобальной обработки неотловленных исключений используется CoroutineExceptionHandler. Он перехватывает исключения, которые не были обработаны внутри корутины, и позволяет залогировать ошибку без краша приложения.

Примеры использования launch в Android

В Android launch применяется повсеместно: от ViewModel до WorkManager. Основной паттерн — использование lifecycleScope во Fragment и viewModelScope в ViewModel для автоматической отмены корутин при завершении жизненного цикла компонента.

kotlin
class ProfileViewModel : ViewModel() {
    private val repository = UserRepository()

    fun loadProfile(userId: String) {
        viewModelScope.launch(Dispatchers.IO) {
            val profile = repository.fetchProfile(userId)
            withContext(Dispatchers.Main) {
                _profileState.update { it.copy(profile = profile) }
            }
        }
    }
}

viewModelScope автоматически отменяет корутины при уничтожении ViewModel. Это исключает утечки и гарантирует, что фоновые операции не продолжаются после потери контекста. Дополнительно можно использовать withContext для переключения между диспетчерами.

Часто задаваемые вопросы

Чем отличается launch от async в Kotlin Coroutines?

launch возвращает Job и не возвращает результат выполнения, а async возвращает Deferred<T> для получения результата. launch используется для fire-and-forget операций, async — когда нужно дождаться и использовать возвращённое значение.

Как отменить корутину, запущенную через launch?

Вызовите job.cancel() на сохранённом объекте Job. Для групповой отмены отмените весь CoroutineScope через scope.cancel(). Корутина должна быть кооперативной — проверять isActive или использовать проверяемые suspend-функции.

Что делать, если launch выбросил исключение?

Используйте try-catch внутри launch блока или передайте CoroutineExceptionHandler в CoroutineContext. Для изоляции ошибок используйте SupervisorJob — тогда исключение в одной дочерней корутине не отменит остальные.

Можно ли запустить launch без CoroutineScope?

Нет, launch — функция-расширение CoroutineScope. Без scope корутина не сможет следовать принципу структурированной конкурентности. Используйте GlobalScope.launch с осторожностью — это создаёт корутину без привязки к жизненному циклу.

Сколько launch корутин можно запустить одновременно?

Количество ограничено пулом потоков диспетчера. Dispatchers.Default использует количество потоков, равное числу ядер CPU. Dispatchers.IO поддерживает до 64 потоков. При запуске большего числа корутин они ставятся в очередь.

Итоги

  • launch — основной билдер для fire-and-forget корутин, возвращающий объект Job
  • Job предоставляет методы управления: cancel(), join(), isActive, isCancelled, isCompleted
  • Структурированная конкурентность гарантирует отмену дочерних корутин при отмене родительской
  • Обработка исключений зависит от типа Job: обычный распространяет ошибки, SupervisorJob изолирует
  • lifecycleScope и viewModelScope — готовые решения для запуска launch в Android
  • CoroutineStart.LAZY откладывает запуск до явного вызова start() или join()
  • launch в Android применяется для сетевых запросов, записи в БД, аналитики и кэширования

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также