问题
In the kotlinx.coroutines
library you can start new coroutine using either launch
(with join
) or async
(with await
). What is the difference between them?
回答1:
launch is used to fire and forget coroutine. It is like starting a new thread. If the code inside the
launch
terminates with exception, then it is treated like uncaught exception in a thread -- usually printed to stderr in backend JVM applications and crashes Android applications. join is used to wait for completion of the launched coroutine and it does not propagate its exception. However, a crashed child coroutine cancels its parent with the corresponding exception, too.async is used to start a coroutine that computes some result. The result is represented by an instance of Deferred and you must use await on it. An uncaught exception inside the
async
code is stored inside the resultingDeferred
and is not delivered anywhere else, it will get silently dropped unless processed. You MUST NOT forget about the coroutine you’ve started with async.
回答2:
I find this guide https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md to be useful. I will quote the essential parts
🦄 coroutine
Essentially, coroutines are light-weight threads.
So you can think of coroutine as something that manages thread in a very efficient way.
🐤 launch
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
}
So launch
starts a background thread, does something, and returns a token immediately as Job
. You can call join
on this Job
to block until this launch
thread completes
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
Conceptually, async is just like launch. It starts a separate coroutine which is a light-weight thread that works concurrently with all the other coroutines. The difference is that launch returns a Job and does not carry any resulting value, while async returns a Deferred -- a light-weight non-blocking future that represents a promise to provide a result later.
So async
starts a background thread, does something, and returns a token immediately as 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")
}
You can use .await() on a deferred value to get its eventual result, but Deferred is also a Job, so you can cancel it if needed.
So Deferred
is actually a Job
. See https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.experimental/-deferred/index.html
interface Deferred<out T> : Job (source)
🦋 async is eager by default
There is a laziness option to async using an optional start parameter with a value of CoroutineStart.LAZY. It starts coroutine only when its result is needed by some await or if a start function is invoked.
来源:https://stackoverflow.com/questions/46226518/what-is-the-difference-between-launch-join-and-async-await-in-kotlin-coroutines