Какие знаешь Coroutine Builders

Ответ

В Kotlin Coroutines есть несколько билдеров для запуска корутин:

  1. launch - запускает корутину без результата (fire-and-forget)
scope.launch {
    // выполнение кода
}
  1. async - запускает корутину с возможностью получить результат через await()
val deferred = scope.async {
    // вычисления
    return@async result
}
val result = deferred.await()
  1. runBlocking - блокирует текущий поток до завершения корутины (используется в основном для тестов или main-функций)
runBlocking {
    // блокирующий код
}
  1. coroutineScope/supervisorScope - создают новую область видимости для корутин с разными стратегиями обработки ошибок.

Ответ 18+ 🔞

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

Вот смотри, есть у них там несколько главных способов эту самую корутину запустить. Как будто у тебя есть машина, но завести её можно по-разному: ключом, с кнопки, с толкача или, в крайнем случае, проводки перемкнуть. Вот и тут так же.

Первый способ — launch. Это как крикнуть соседу: «Эй, Вась, сходи за пивом!» — и забыть. Ты его запустил, он там что-то делает, а ты дальше своё дело делаешь. Результата от него не ждёшь, просто чтобы дело сделал. Если он по пути упадёт в люк — ну, бывает, сам виноват, не смотрел под ноги. В коде это выглядит так:

scope.launch {
    // выполнение кода
}

Всё, пустил и пошёл. Классический «запустил и забыл». Удобно, когда тебе не нужен ответ, а нужно просто какое-то фоновое действие.

Второй — async. А вот это уже хитрая жопа. Ты уже не просто посылаешь Васю за пивом, а говоришь: «Вась, сходи за пивом и точно скажи, сколько стоит». То есть ты ждёшь от него ответ. Он уходит, ты ждёшь, он возвращается и говорит: «Двести рублей». Или не возвращается, потому что его в отделке задержали — но это уже ошибка. В коде это:

val deferred = scope.async {
    // вычисления
    return@async result
}
val result = deferred.await() // Тут сидишь и ждёшь, как дурак, пока Вася вернётся

Ключевое — этот await(). Он блокирует твою корутину (не поток!) до тех пор, пока Вася-async не притащит результат. Используется, когда нужно параллельно посчитать несколько штук и потом собрать всё вместе.

Третий — runBlocking. О, это отдельная песня. Ёперный театр! Это как взять и пригвоздить себя к стулу на время выполнения задачи. Ты говоришь: «Я никуда не пойду, пока Вася не вернётся с пивом!». Весь текущий поток встаёт колом и ждёт. Использовать это нужно с умом, а то доверия ебать ноль к такому подходу в нормальном асинхронном коде. Только для тестов или для функции main, чтобы всё не разбежалось раньше времени.

runBlocking {
    // блокирующий код
}

Четвёртая парочка — coroutineScope и supervisorScope. Вот тут уже начинается магия по-взрослому. Это как создать для Васи и его братвы отдельную комнату, где они могут делать свои дела.

  • coroutineScope — это строгая комната. Если один из них (например, Петя) накосячил и упал с криком «ёбана-в-рот!», то вся комната немедленно закрывается, а всех остальных вышвыривают с ошибкой. Жёстко, но справедливо.
  • supervisorScope — это комната с более понимающим старшим. Если Петя накосячил, его одного и выкинут. А Васю и других не тронут, пусть своё пиво дальше носят. Часто именно это и нужно.

Короче, суть в том, чтобы не путать, когда тебе нужно просто сделать дело (launch), а когда ещё и результат получить (async). А runBlocking — это такой большой молоток, которым лучше по гвоздям стучать, а не по микроскопу. Ну и про области видимости не забывай, а то все твои корутины разбегутся, как тараканы от света, и потом ищи-свищи.