挂起函数调用顺序
- 在协程中顺序调用多个挂起函数 这多个挂起函数执行的顺序和常规代码中一样 默认都是顺序执行的
常规代码中函数调用:
fun main() {
// 例子:普通函数的调用 执行顺序
normalOne()
normalTwo()
}
// 普通函数1
fun normalOne() {
Thread.sleep(500L)
println("普通函数1执行完毕")
}
// 普通函数2
fun normalTwo() {
Thread.sleep(500L)
println("普通函数2执行完毕")
}
挂起函数调用:
fun main() = runBlocking {
// 例子:如果我们想获取两个挂起函数的总用时
val totalTime = measureTimeMillis {
doSomethingOne()
doSomethingTwo()
}
println(" 总耗时:$totalTime ")
}
// 挂起函数1
suspend fun doSomethingOne() {
delay(1000L)
println("挂起函数1执行完毕")
}
// 挂起函数2
suspend fun doSomethingTwo() {
delay(1000L)
println("挂起函数2执行完毕")
}
执行结果:
挂起函数1执行完毕
挂起函数2执行完毕
总耗时:2015
使用async并发
- 使用场景 如果调用的多个函数 没有之间的相互依赖的关系 无需同步 异步执行更高效更省时
从概念上讲 async类似于launch async启动一个单独的协程(轻量级) 不同之处是,launch返回job对象并不携带任何运行结果值 而async返回一个轻量级非阻塞的Deferred对象 可用于在最后取出返回值 可以通过调用Deferred的await()方法来获取最终的结果 同时它也实现了Job接口 也可以根据需要去取消它
fun main() = runBlocking {
val time = measureTimeMillis {
val one = async { suspendFunctionOne() }
val two = async { suspendFunctionTwo() }
println(" 挂起函数1返回结果 ${one.await()} 挂起函数2返回结果 ${two.await()} ")
}
println(" async 并发执行总耗时:$time ")
}
// 挂起函数1
suspend fun suspendFunctionOne(): Int {
println(" 挂起函数1执行开始 ")
delay(1000L)
println(" 挂起函数1执行结束 ")
return 22
}
// 挂起函数2
suspend fun suspendFunctionTwo(): Int {
println(" 挂起函数2执行开始 ")
delay(1000L)
println(" 挂起函数2执行结束 ")
return 33
}
执行结果返回:
挂起函数1执行开始
挂起函数2执行开始
挂起函数1执行结束
挂起函数2执行结束
挂起函数1返回结果 22 挂起函数2返回结果 33
async 并发执行总耗时:1036
- 运行耗时几乎是减半了,因为这两个协程是同时运行,总的耗时时间可以说是取决于耗时最长的任务。需要注意,协程的并发总是显式的
惰性启动async
- 只有在主动调用 Deferred 的 await() 或者 start() 方法时才会启动协程
fun main() = runBlocking {
val time = measureTimeMillis {
val one = async(start = CoroutineStart.LAZY) { doSomething1() }
val two = async(start = CoroutineStart.LAZY) { doSomething2() }
one.start()
two.start()
println(" 函数1返回结果 ${one.await()} 函数2返回结果 ${two.await()} ")
}
println(" 总耗时:$time ")
}
// 挂起函数1
suspend fun doSomething1(): Int {
println(" 挂起函数1执行开始 ")
delay(1000L)
println(" 挂起函数1执行结束 ")
return 11
}
// 挂起函数2
suspend fun doSomething2(): Int {
println(" 挂起函数2执行开始 ")
delay(1000L)
println(" 挂起函数2执行结束 ")
return 22
}
执行结果:
挂起函数1执行开始
挂起函数2执行开始
挂起函数1执行结束
挂起函数2执行结束
函数1返回结果 11 函数2返回结果 22
总耗时:1035
异步风格的函数
/**
* 异步风格的async函数
* 通过GlobalScope.async{}引用的异步协程生成器来调用
* 并不是挂起函数 所以说可以在任何地方调用
*/
fun main() {
val time = measureTimeMillis {
// 调用下面函数意味着用异步的形式来执行操作
val oneAsync = someThingOneAsync()
val twoAsync = someThingTwoAsync()
// 因为await()是挂起函数 所以需要在协程和其它挂在函数中执行
runBlocking {
println(" 函数1结果:${oneAsync.await()} 函数2结果:${twoAsync.await()} ")
}
}
println(" 总耗时:$time ")
}
fun someThingOneAsync() = GlobalScope.async { doOne() }
fun someThingTwoAsync() = GlobalScope.async { doTwo() }
// 挂起函数1
suspend fun doOne(): String {
println("挂起函数1开始执行")
delay(1000L)
println("挂起函数1执行完毕")
return "小黄一号"
}
// 挂起函数2
suspend fun doTwo(): String {
println("挂起函数2开始执行")
delay(1000L)
println("挂起函数2执行完毕")
return "小黄二号"
}
问题点:如果在 val oneAsync = someThingOneAsync() 和 oneAsync.await() 之间的代码逻辑出现错误 出现异常 导致现有的任务会被停掉 此时全局的错误处理者会捕获异常并不会让程序停止 那就意味着 someThingOneAsync()函数仍然还在后台继续运行(因为其协程作用域是GlobalScope) 之后的代码逻辑还会继续执行
- 要想解决上述问题 可以使用async结构化并发
async结构化并发
- 如果 concurrentSum() 函数发生错误并引发异常,则在其作用域中启动的所有协程都将被取消
/**
* async结构化并发
*/
fun main() = runBlocking<Unit> {
val time = measureTimeMillis {
println("成绩总和:${coroutineSum()} ")
}
println("总耗时 $time ")
}
suspend fun coroutineSum(): Int = coroutineScope {
val async1 = async {
doSomeOne()
}
val async2 = async {
doSomeTwo()
}
async1.await() + async2.await()
}
// 挂起函数1
suspend fun doSomeOne(): Int {
println("挂起函数1开始执行")
delay(1000L)
println("挂起函数1结束执行")
return 10
}
// 挂起函数2
suspend fun doSomeTwo(): Int {
println("挂起函数2开始执行")
delay(1000L)
println("挂起函数2结束执行")
return 11
}
执行结果:
挂起函数1开始执行
挂起函数2开始执行
挂起函数1结束执行
挂起函数2结束执行
成绩总和:21
总耗时 1035
取消例子:
// 机构化并发 异常取消机制例子
fun main() = runBlocking<Unit> {
try {
coroutineTest()
} catch (e: Exception) {
println("异常捕获${e.message}")
}
}
suspend fun coroutineTest(): Int = coroutineScope {
val one = async<Int> {
try {
delay(Long.MAX_VALUE)
22
} finally {
println("finally执行")
}
}
val two = async<Int> {
println("异常操作执行")
throw ArithmeticException()
}
one.await() + two.await()
}
执行结果:
异常操作执行
finally执行
异常捕获null
谢谢亲们的关注支持 记得点赞哦!
网友评论