В библиотеке 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 только тогда, когда его результат необходим кому-то или если запускается функция запуска.