Подтвердить что ты не робот

В чем разница между запуском/соединением и асинхронным/ожиданием в сопрограммах Kotlin

В библиотеке kotlinx.coroutines вы можете запустить новую сопрограмму с помощью launchjoin) или async (с помощью await). В чем разница между ними?

4b9b3361

Ответ 1

  • launch используется для огня и забывания сопрограммы. Это похоже на начало новой темы. Если код внутри launch заканчивается с исключением, то он рассматривается как неотображенное исключение в потоке - обычно печатается на stderr в backend JVM-приложениях и вызывается приложения Android. join используется для ожидания завершения запущенной сопрограммы и не распространяется на ее исключение. Однако разбитый дочерний сопрограмм также отменяет его родительское с соответствующим исключением.

  • async используется для запуска coroutine, который вычисляет некоторый результат. Результат представлен экземпляром Deferred, и вы должны использовать await. Неоткрытое исключение внутри кода async сохраняется внутри результирующего Deferred и не отправляется нигде, оно будет автоматически отбрасываться, если только оно не обработано. Вы НЕ ДОЛЖНЫ забыть о том, что coroutine вы начали с асинхронного.

Ответ 2

Я нахожу это руководство https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md полезным. Я приведу основные части

🦄 сопрограмма

По сути, сопрограммы - это легкие потоки.

Итак, вы можете думать о сопрограмме как о том, что управляет потоком очень эффективным способом.

🐤 запуск

fun main(args: Array<String>) {
    launch { // launch new coroutine in background and continue
        delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
        println("World!") // print after delay
    }
    println("Hello,") // main thread continues while coroutine is delayed
    Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}

Итак, launch запускает фоновый поток, что-то делает и сразу же возвращает токен как Job. Вы можете вызвать join в этом Job для блокировки до тех пор, пока поток launch не завершится

fun main(args: Array<String>) = runBlocking<Unit> {
    val job = launch { // launch new coroutine and keep a reference to its Job
        delay(1000L)
        println("World!")
    }
    println("Hello,")
    job.join() // wait until child coroutine completes
}

🦆 async

Концептуально, async - это как запуск. Он запускает отдельную сопрограмму, которая представляет собой легкую нить, которая работает одновременно со всеми другими сопрограммами. Разница заключается в том, что запуск возвращает Job и не несет никакого результирующего значения, в то время как async возвращает Отложенное - легкое неблокирующее будущее, которое представляет обещание предоставить результат позже.

Итак, async запускает фоновый поток, делает что-то и возвращает токен сразу как Deferred.

fun main(args: Array<String>) = runBlocking<Unit> {
    val time = measureTimeMillis {
        val one = async { doSomethingUsefulOne() }
        val two = async { doSomethingUsefulTwo() }
        println("The answer is ${one.await() + two.await()}")
    }
    println("Completed in $time ms")
}

Вы можете использовать .await() для отложенного значения, чтобы получить его конечный результат, но Deferred также является Job, поэтому вы можете отменить его при необходимости.

Итак, Deferred на самом деле a Job. См. https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html

interface Deferred<out T> : Job (source)

🦋 асинхронно по умолчанию

Существует опция laziness для асинхронизации с использованием необязательного параметра start со значением CoroutineStart.LAZY. Он запускает coroutine только тогда, когда его результат необходим кому-то или если запускается функция запуска.