一、默认顺序调用
在协程中的,挂起函数像常规的代码⼀样顺序都是默认的。
suspend fun doSomethingUsefulOne(): Int {
delay(1000L)
return 13
}
suspend fun doSomethingUsefulTwo(): Int {
delay(1000L)
return 14
}
fun main() = runBlocking {
val time = measureTimeMillis {
val one = doSomethingUsefulOne()
val two = doSomethingUsefulTwo()
println("The answer is ${one + two}")
}
println("Completed in $time ms")
}
输出:
The answer is 27
Completed in 2042 ms
二、使用 async 并发
async 就类似于 launch。它启动了⼀个单独的协程,这是⼀个轻量级的线程并与其它所有的协程⼀起并发的工作。不同之处在于 launch 返回⼀个 Job 并且不附带任何结果值,而 async 返回⼀个 Deferred —— ⼀个轻量级的非阻塞 future,这代表了⼀个将会在稍后提供结果的 promise。你可以使用 .await() 在⼀个延期的值上得到它的最终结果,但是 Deferred 也是⼀个 Job ,所以如果需要的话,你可以取消它。
fun main() = runBlocking {
val time = measureTimeMillis {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")
}
输出:
The answer is 27
Completed in 1022 ms
因为两个协程并发执行,速度快了两倍。请注意,使用协程进行并发总是显式的。
三、惰性启动的 async
async 可以通过将 start 参数设置为 CoroutineStart.LAZY 而变为惰性的。在这个模式下,只有结果 通过 await 获取的时候协程才会启动,或者在 Job 的 start 函数调用的时候。
fun main() = runBlocking {
val time = measureTimeMillis {
val one = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
val two = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
one.start()
two.start()
println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")
}
输出:
The answer is 27
Completed in 1028 ms
如果我们只是在 println 中调用 await,而没有在单独的协程中调用 start,这将会导致顺序行为,直到 await 启动该协程 执行并等待至它结束。
四、async风格的函数
使用 async 协程建造器并带有⼀个显式的 GlobalScope 引用。函数不是挂起函数,可以在任何地方使用,但是是异步执行。在kotlin中不推荐使用。
fun somethingUsefulOneAsync() = GlobalScope.async { doSomethingUsefulOne() }
五、使用 async 的结构化并发
由于 async 被定义为了 CoroutineScope 上 的扩展,我们需要将它写在作用域内,并且这是 coroutineScope 函数所提供的。
suspend fun concurrentSum(): Int = coroutineScope {
val one = async {
doSomethingUsefulOne()
}
val two = async {
doSomethingUsefulTwo()
}
one.await() + two.await()
}
如果在 concurrentSum 函数内部发生了错误,并且它抛出了⼀个异常,所有在作用域中启动的协程都会被取消。
fun main() = runBlocking {
try {
println("The answer is ${failedConcurrentSum()}")
} catch (e: ArithmeticException) {
println("Computation failed with ArithmeticException")
}
}
suspend fun failedConcurrentSum(): Int = coroutineScope {
val one = async {
try {
delay(Long.MAX_VALUE)
13
} finally {
println("First child was cancelled")
}
}
val two = async {
println("Second child throws an exception")
throw ArithmeticException()
14
}
one.await() + two.await()
}
输出:
Second child throws an exception
First child was cancelled
Computation failed with ArithmeticException
网友评论