Coroutine Builder: что это, типы билдеров сопрограмм и как работают

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

Coroutine Builder — функции Kotlin Coroutines, которые создают и запускают сопрограммы, определяя способ их выполнения. Билдеры launch, async, runBlocking и produce покрывают разные сценарии: от фоновых задач до параллельных вычислений с возвратом результата. По данным JetBrains, 2024, Coroutine Builder является основой корутинной модели, обеспечивая структурированную конкурентность и управление жизненным циклом.

Главное

  • Coroutine Builder — функция, создающая сопрограмму в определённом CoroutineScope
  • launch — запускает корутину без возврата результата, возвращает объект Job
  • async — запускает корутину с возвратом Deferred, позволяя получить результат через await()
  • runBlocking — блокирует текущий поток, используемый как мост между blocking и suspending кодом
  • produce — создаёт корутину с каналом для потоковой передачи данных (устарел в пользу Flow)

Что такое Coroutine Builder?

Coroutine Builder — это функция-расширение Kotlin, которая принимает CoroutineScope и suspend-блок, создавая и запуская новую сопрограмму. Каждый билдер определяет, как корутина будет выполняться: с возвратом результата или без, с блокировкой потока или асинхронно. Билдеры являются точками входа в корутинную модель языка.

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

kotlin
import kotlinx.coroutines.*

fun main() = runBlocking {
    // Builders run inside CoroutineScope
    val job = launch {
        delay(1000L)
        println("World!")
    }
    println("Hello,")
    job.join()
}

Основные типы билдеров сопрограмм

Kotlin предоставляет четыре встроенных билдера сопрограмм: launch, async, runBlocking и produce. Каждый из них имеет свой возвращаемый тип и область применения. Для мобильной разработки под Android основными являются launch и async — они работают неблокирующим образом и интегрируются с архитектурными компонентами.

БилдерВозвращаемый типБлокировка потокаСценарий
launchJobНетFire-and-forget задачи
asyncDeferred<T>НетПараллельные вычисления
runBlockingTДаТесты, main-функция
produceReceiveChannel<E>НетПотоковая передача (deprecated)

Каждый билдер принимает дополнительные параметры: CoroutineStart (стратегия запуска), CoroutineContext (диспетчер, исключения) и именованный блок кода. По умолчанию корутина запускается немедленно (CoroutineStart.DEFAULT).

launch: fire-and-forget запуск

launch — наиболее используемый билдер в Android-разработке. Он запускает сопрограмму, которая не возвращает результат, и возвращает объект Job для управления её жизненным циклом. Это идеальный выбор для операций, где нужен только побочный эффект: сохранение в БД, отправка аналитики, обновление UI.

Синтаксис и использование launch

Билдер launch принимает CoroutineScope, необязательный CoroutineContext и suspend-блок. Возвращаемый Job позволяет отменить корутину, дождаться её завершения или проверить статус.

kotlin
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
val job: Job = scope.launch(CoroutineStart.LAZY) {
    val data = fetchFromNetwork()
    saveToDatabase(data)
}
job.start()
job.join()

Параметр CoroutineStart.LAZY откладывает запуск до явного вызова start() или join(). Это полезно для отложенной инициализации и условного запуска. Для стандартного немедленного запуска используется CoroutineStart.DEFAULT или параметр опускается.

async: параллельные вычисления с результатом

async — билдер, возвращающий Deferred<T> — асинхронное обещание результата. Вызов await() приостанавливает корутину до получения результата, не блокируя поток. Это основной механизм для параллельных задач в корутинах Kotlin.

Запуск двух запросов параллельно

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

kotlin
suspend fun fetchUserData(): UserData {
    val deferred1 = CoroutineScope(Dispatchers.IO).async { api.getProfile() }
    val deferred2 = CoroutineScope(Dispatchers.IO).async { api.getSettings() }
    val deferred3 = CoroutineScope(Dispatchers.IO).async { api.getNotifications() }
    return UserData(
        profile = deferred1.await(),
        settings = deferred2.await(),
        notifications = deferred3.await()
    )
}

Deferred наследуется от Job, поэтому async поддерживает все операции жизненного цикла: отмену, ожидание завершения, обработку исключений. При отмене scope дочерние Deferred корутины отменяются автоматически.

runBlocking: мост в blocking-мир

runBlocking — единственный билдер, который блокирует текущий поток до завершения корутины. Он создаёт новый CoroutineScope и запускает переданную сопрограмму, блокируя вызывающий поток. Используется в точках входа main(), в тестах и при интеграции с blocking-кодом.

Когда runBlocking необходим

runBlocking оправдан в трёх сценариях: точка входа приложения (main), юнит-тесты suspend-функций и интеграция с callback-based библиотеками, где нельзя использовать suspend. В production-коде Android использование runBlocking на главном потоке категорически не рекомендуется.

kotlin
class CoroutineTest {
    @Test
    fun `test suspend function`() = runBlocking {
        val result = mySuspendFunction()
        assertEquals("expected", result)
    }
}

Для тестов рекомендуется использовать kotlinx-coroutines-test с TestCoroutineDispatcher вместо runBlocking — это обеспечивает контроль времени и избегает блокировок в тестовой среде.

Как выбрать подходящий билдер

Выбор Coroutine Builder зависит от возвращаемого результата и сценария выполнения. Если операция не требует возврата данных — используйте launch. Если нужен результат асинхронной операции — async. runBlocking применяйте только для bridging, а produce замените на Flow для реактивных потоков.

Практические рекомендации для Android

В Android-проектах с использованием Kotlin Coroutines основная пара билдеров — launch и async. launch используется в ViewModel и UseCases для запуска корутин, а async — для параллельных запросов к сети или БД. Современные библиотеки (Ktor, Room) уже поддерживают suspend-функции, что минимизирует необходимость в прямом использовании async.

  • launch — для fire-and-forget (логирование, аналитика, кэширование)
  • async — для параллельных запросов с объединением результатов
  • runBlocking — только в main() и тестах (не в production на Main-потоке)
  • produce — заменить на Flow / SharedFlow / StateFlow

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

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

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

Можно ли использовать runBlocking в Android Activity?

Не рекомендуется. runBlocking на главном потоке вызывает ANR и блокирует UI. Используйте lifecycleScope.launch внутри Activity и Fragment — это встроенное решение без блокировок.

Что возвращает билдер launch?

Билдер launch возвращает объект Job, который позволяет контролировать жизненный цикл корутины: отменить (cancel), дождаться завершения (join), проверить статус (isActive, isCompleted, isCancelled).

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

Deferred<T> — это асинхронное обещание результата, возвращаемое билдером async. Он наследуется от Job и добавляет методы await() для получения результата, getCompleted() для неблокирующего доступа и getCompletionExceptionOrNull() для проверки исключения.

Как запустить launch с задержкой?

Используйте параметр CoroutineStart.LAZY: scope.launch(start = CoroutineStart.LAZY) { ... }. Затем вызовите job.start() или job.join() для фактического запуска. Это полезно для отложенной инициализации и условного выполнения корутин.

Итоги

  • Coroutine Builder — функция создания сопрограммы, которая определяет способ её выполнения и возвращаемый тип
  • launch — основной билдер для задач без возврата результата, возвращает Job для управления корутиной
  • async — билдер для параллельных вычислений, возвращает Deferred с возможностью await() результата
  • runBlocking — блокирующий билдер для main() и тестов, не рекомендуется на главном потоке Android
  • Структурированная конкурентность гарантирует автоматическую отмену дочерних корутин при отмене scope
  • produce устарел — используйте Flow, SharedFlow или StateFlow для реактивных потоков данных
  • Выбор билдера зависит от сценария: fire-and-forget → launch, параллельные данные → async, bridging → runBlocking

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

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

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

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