В библиотеке kotlinx.coroutines вы можете запустить новую сопрограмму с помощью launch (с join) или async (с помощью await). В чем разница между ними?
В чем разница между запуском/соединением и асинхронным/ожиданием в сопрограммах Kotlin
Ответ 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 только тогда, когда его результат необходим кому-то или если запускается функция запуска.