Kotlin组合挂起函数分为默认顺序调用、使用 async 并发、惰性启动的 async、async 风格的函数、使用 async 的结构化并发、取消始终通过协程的层次结构来进行传递:
package group
import kotlinx.coroutines.*
import kotlin.system.measureTimeMillis
/**
* 使用协程进行并发总是显式的。
*/
suspend fun main() = runBlocking<Unit>{
println("======> example 1:默认顺序调用")
// 根据第一个函数调用结果来决定是否调用第二个函数
// 这些代码都是运行在协程中的,顺序都是默认的
val one = doSomethingUsefulOne()
val two = doSomethingUsefulTwo()
println("The answer is ${one + two}")
println("======> example 2:使用 async 并发")
// launch 返回一个 Job 并且不附带任何结果值
// async 返回一个 Deferred —— 一个轻量级的非阻塞 future
// Deferred 也是一个 Job,使用 .await() 可以得到一个延期的值,也可以取消它。
// doSomethingUsefulOne和doSomethingUsefulTwo 没有任何俩,使用async可以尽快得到值
// 执行速度比example 1 快一倍
val time = measureTimeMillis {
val ones = async { doSomethingUsefulOne() }
val twos = async { doSomethingUsefulTwo() }
println("The answer is ${ones.await() + twos.await()}")
}
println("Completed in $time ms")
println("======> example 3:惰性启动的 async")
// async 可以通过将 start 参数设置为 CoroutineStart.LAZY 而变为惰性的。
// 只有通过 await 获取的时候协程才会启动,或者在 Job 的 start 函数调用的时候。
// 只是在 println 中调用 await,而没有在单独的协程中调用 start ===> 顺序行为
// 计算一个值涉及挂起函数时, async(start = CoroutineStart.LAZY) ==替代 ==>标准库中的 lazy 函数。
val time3 = measureTimeMillis {
val onel = async(start = CoroutineStart.LAZY) { doSomethingUsefulOne() }
val twol = async(start = CoroutineStart.LAZY) { doSomethingUsefulTwo() }
// 执行一些计算
onel.start() // 启动第一个
twol.start() // 启动第二个
println("The answer is ${onel.await() + twol.await()}")
}
println("Completed in $time3 ms")
println("======> example 4:async 风格的函数")
//定义 doSomethingUsefulOne 和 doSomethingUsefulTwo 异步风格的函数
// 使用 async 协程建造器并带有一个显式的 GlobalScope 引用 ==>GlobalScope.async
// 这些并不是挂起函数,可以再任何地方使用,异步(并发)执行,并不推荐使用
// 这里会造成全局捕获异常,但是该程序会继续执行,也就是somethingUsefulOneAsync 仍然在后台执行
val time5 = measureTimeMillis {
// 我们可以在协程外面启动异步执行
val onell = somethingUsefulOneAsync()
val twoll = somethingUsefulTwoAsync()
// 但是等待结果必须调用其它的挂起或者阻塞
// 当我们等待结果的时候,这里我们使用 `runBlocking { …… }` 来阻塞主线程
runBlocking {
println("The answer is ${onell.await() + twoll.await()}")
}
}
println("Completed in $time5 ms")
println("======> example 5:使用 async 的结构化并发")
// async 被定义为 CoroutineScope 上的扩展
// 将携程卸载作用域内,由coroutineScope 函数提供
// 即使concurrentSum 函数内部发生了错误,它所在作用域中启动的协程都会被取消
val time6 = measureTimeMillis {
println("The answer is ${concurrentSum()}")
}
println("Completed in $time6 ms")
println("======> example 6:取消始终通过协程的层次结构来进行传递")
// 其中一个子协程(即 two)失败,第一个 async 以及等待中的父协程都会被取消:
try {
failedConcurrentSum()
} catch(e: ArithmeticException) {
println("Computation failed with ArithmeticException")
}
}
suspend fun doSomethingUsefulOne(): Int {
delay(1000L) // 假设我们在这里做了一些有用的事
return 13
}
suspend fun doSomethingUsefulTwo(): Int {
delay(1000L) // 假设我们在这里也做了一些有用的事
return 29
}
// somethingUsefulOneAsync 函数的返回值类型是 Deferred<Int>
fun somethingUsefulOneAsync() = GlobalScope.async {
doSomethingUsefulOne()
}
// somethingUsefulTwoAsync 函数的返回值类型是 Deferred<Int>
fun somethingUsefulTwoAsync() = GlobalScope.async {
doSomethingUsefulTwo()
}
suspend fun concurrentSum(): Int = coroutineScope {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
one.await() + two.await()
}
/**
* 其中一个子协程(即 two)失败,第一个 async 以及等待中的父协程都会被取消:
*/
suspend fun failedConcurrentSum(): Int = coroutineScope {
val one = async<Int> {
try {
delay(Long.MAX_VALUE) // 模拟一个长时间的运算
42
} finally {
println("First child was cancelled")
}
}
val two = async<Int> {
println("Second child throws an exception")
throw ArithmeticException()
}
one.await() + two.await()
}