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

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

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

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

Я считаю это руководство 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 – это как запуск. Он запускает отдельную сопрограмму, которая представляет собой легкую нить, которая работает одновременно со всеми другими сопрограммами. Разница заключается в том, что запуск возвращает 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 на самом деле является 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. Он запускает сопрограмму только тогда, когда ее результат необходим некоторому ожиданию или если вызывается функция запуска.