协程学习(四)协程简单的使用 coroutineScope 与 supervisorScope

我学习协程的历程

1.协程学习(一)一个最简单的协程例子

2.协程学习(二)协程简单的使用launch async join await

3.协程学习(三)协程简单的使用 CoroutineStart

4.协程学习(四)协程简单的使用 coroutineScope 与 supervisorScope

我们在 协程学习(二) 中遇到一个问题,那就是顺序请求3个接口的问题,我们把这个问题再描述一下

现在有3个接口,要求是顺序的请求这3个接口,

kotlin 复制代码
suspend fun Func1()= withContext(Dispatchers.IO){
    delay(2000)
}

suspend fun Func2()= withContext(Dispatchers.IO){
    delay(1000)
}
suspend fun Func3()= withContext(Dispatchers.IO){
    delay(3000)
}

在这个基础上我们再增加一个逻辑,那就是这3个接口只要有一个接口调用失败,那么所有的接口都不需要等待了,一起失败

这个问题就引出了协程的作用域的概念了

coroutineScope 作用域,子协程中只要有一个协程失败,其他兄弟协程也会失败

案例如下

现在 Func2 是耗时最少的任务,现在让Func2抛出异常看一下结果

scss 复制代码
@JvmStatic
fun main(a:Array<String>) {
    runBlocking {
        coroutineScope {
            launch {
                Func1()
                println("------------Func1执行完毕了-----------")
            }
            launch {
                Func2()
                println("------------Func2执行完毕了-----------")
                throw NullPointerException("抛出异常")
            }
            launch {
                Func3()
                println("------------Func3执行完毕了-----------")
            }
        }
        println("------------coroutineScope parent 执行完毕了-----------")
    }
}
结果:

------------Func2执行完毕了-----------
Exception in thread "main" java.lang.NullPointerException: 抛出异常
	at com.tsm.opencv.TsmTest$main$1$1$2.invokeSuspend(TsmTest.kt:33)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:280)
	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
	at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
	at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
	at com.tsm.opencv.TsmTest.main(TsmTest.kt:24)

Process finished with exit code 1

发现只有第二个执行任务执行完成了,任务1 和 任务3执行完成并没有打印就已经退出了, 现在让耗时时间最久的任务3抛出异常

scss 复制代码
@JvmStatic
fun main(a:Array<String>) {
    runBlocking {
        coroutineScope {
            launch {
                Func1()
                println("------------Func1执行完毕了-----------")
            }
            launch {
                Func2()
                println("------------Func2执行完毕了-----------")
            }
            launch {
                Func3()
                println("------------Func3执行完毕了-----------")
                throw NullPointerException("抛出异常")
            }
        }
        println("------------coroutineScope parent 执行完毕了-----------")
    }
}
结果:
------------Func2执行完毕了-----------
------------Func1执行完毕了-----------
------------Func3执行完毕了-----------
Exception in thread "main" java.lang.NullPointerException: 抛出异常
	at com.tsm.opencv.TsmTest$main$1$1$3.invokeSuspend(TsmTest.kt:37)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:280)
	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
	at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
	at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
	at com.tsm.opencv.TsmTest.main(TsmTest.kt:24)

Process finished with exit code 1

这里可以看到任务1 2 3 都执行完毕了,但是 coroutineScope 后续代码扔没有执行,至于为什么没有执行就涉及到任务协程的异常捕获的相关问题了,这里只需要知道在使用 coroutineScope 作用域的情况下如果子协程中一个任务失败了,其他兄弟协程也会被取消

supervisorScope 作用域,子协程中有一个协程失败,其他兄弟协程不会受到影响,

我们先让执行速度最慢的任务 3 抛出异常

scss 复制代码
@JvmStatic
fun main(a:Array<String>) {
    runBlocking {
        supervisorScope {
            launch {
                Func1()
                println("------------Func1执行完毕了-----------")
            }
            launch {
                Func2()
                println("------------Func2执行完毕了-----------")
            }
            launch {
                Func3()
                println("------------Func3执行完毕了-----------")
                throw NullPointerException("抛出异常")
            }
        }
        println("------------coroutineScope parent 执行完毕了-----------")
    }
}
结果:

------------Func2执行完毕了-----------
------------Func1执行完毕了-----------
------------Func3执行完毕了-----------
Exception in thread "main" java.lang.NullPointerException: 抛出异常
	at com.tsm.opencv.TsmTest$main$1$1$3.invokeSuspend(TsmTest.kt:37)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:280)
	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
	at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
	at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
	at com.tsm.opencv.TsmTest.main(TsmTest.kt:24)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@16f65612, BlockingEventLoop@311d617d]
------------supervisorScope parent 执行完毕了-----------

Process finished with exit code 0

可以看到虽然任务3虽然抛出异常了,但是在 supervisorScope 执行完毕后的打印还是出来了,这与 coroutineScope 表现是不同的,我们继续往耗时最少任务2抛出异常

scss 复制代码
@JvmStatic
fun main(a:Array<String>) {
    runBlocking {
        supervisorScope {
            launch {
                Func1()
                println("------------Func1执行完毕了-----------")
            }
            launch {
                Func2()
                println("------------Func2执行完毕了-----------")
                throw NullPointerException("抛出异常")
            }
            launch {
                Func3()
                println("------------Func3执行完毕了-----------")
            }
        }
        println("------------supervisorScope parent 执行完毕了-----------")
    }
}
结果:
------------Func2执行完毕了-----------
Exception in thread "main" java.lang.NullPointerException: 抛出异常
	at com.tsm.opencv.TsmTest$main$1$1$2.invokeSuspend(TsmTest.kt:33)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:280)
	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
	at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
	at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
	at com.tsm.opencv.TsmTest.main(TsmTest.kt:24)
	Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@16f65612, BlockingEventLoop@311d617d]
------------Func1执行完毕了-----------
------------Func3执行完毕了-----------
------------supervisorScope parent 执行完毕了-----------

Process finished with exit code 0

这段代码中虽然耗时最少的任务2在执行完成后抛出异常,但是后续任务 1 与任务3 还是执行完成了,而且 supervisorScope 挂起被恢复后也被执行了

到了这里协程中比较常用协同作用域就介绍完了,但是这里面案例还是有一些问题,那就是异常的处理,关于异常的相关介绍,在后续的文章中会介绍到

相关推荐
weixin_440784118 小时前
【HandlerThread实现原理】
android·java·开发语言
唐诺10 小时前
Android USB ADB 调试方案完全解析
android·adb·usb
寰宇星城14 小时前
AppActuator - 让 AI Agent 直接理解并操作运行中的 Android App
android
波罗丁牌15 小时前
uni-app 实现视频聊天、屏幕分享,支持Android、HarmonyOS、iOS
android·uni-app·音视频
峥嵘life15 小时前
Android WiFi 热点 Channel 信道 和 Frequency 频率 转换总结
android·开发语言
jieyucx15 小时前
【高级利用】条件竞争与逻辑漏洞:与服务器赛跑的艺术
android·运维·服务器·web安全·文件上传
凡泰AI17 小时前
APP同时覆盖了iOS、安卓和鸿蒙,如何选择混合开发架构才能减少重复建设,提高功能上线效率~
android·ios·harmonyos·mpaas·uni·小程序容器
叶辞树17 小时前
死锁问题分析
android
TimeFine18 小时前
让 Codex “用上”Android Studio:JetBrains MCP Server 接入与实践
android
__Witheart__19 小时前
3568 Android 设置首次烧录后 usb otg 口模式
android·adb·rockchip