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 {
    // Білдери виконуються всередині CoroutineScope
    val job = launch {
        delay(1000L)
        println("Світе!")
    }
    println("Привіт,")
    job.join()
}

Основні типи білдерів корутин

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

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

Кожен білдер приймає додаткові параметри: 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-бібліотеками, де не можна використовувати 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

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