kotlin的父子协程关系
关于协程的父子关系,从如下一段代码的运行结果来分析
import kotlinx.coroutines.* import java.net.URL suspend fun fetchResponse(code: Int, delay: Int) = coroutineScope { try { val response = async { URL("http://httpstat.us/$code?sleep=$delay").readText() }.await() println(response) } catch(ex: CancellationException) { println("${ex.message} for fetchResponse $code") } } runBlocking { val handler = CoroutineExceptionHandler {_, ex -> println("exception handled: ${ex.message}") } val job = launch(Dispatchers.IO + SupervisorJob() + handler) { // 协程1 launch{fetchResponse(202, 1000)} // 协程2 launch{fetchResponse(404, 2000)} // 协程3 launch{fetchResponse(200, 3000)} // 协程4 } job.join() }
如上运行的结果是:
202 Accepted
Parent job is Cancelling for fetchResponse 200
exception handled: http://httpstat.us/404?sleep=2000
按照定义:使用 SupervisorJob,子协程的失败不会影响其余子协程。一个 SupervisorJob不会取消它自己或它的子协程。而且,SupervisorJob也不会传播异常,它会让子协程自己处理异常。
但是上述在协程3发生异常之后,协程4竟然被取消了;也就是说在launch中的SupervisorJob()不起作用?
如果说不起作用的话,那么异常应该继续往外传播,可是异常却在handler拦住了
这里我们先分析各个协程是job还是SupervisorJob
fetchResponse是由coroutineScope包着,所以coroutineScope是job类型
launch会创建一个新的协程默认Job,所以协程234均为Job
那么协程1是什么类型的呢?从运行结果显示应该是Job而不是SupervisorJob。那么为什么是Job?
因为一个新的协程总是会被赋予一个新的Job(),它在这个例子中覆盖了SupervisorJob。SupervisorJob是通过 scope.launch创建的协程的parentjob
这也就解释了为什么协程3异常的时候,他的兄弟协程4被取消;协程1向上抛出异常,但是被他的父协程SupervisorJob拦住了让他自己处理异常,所以协程1只能将异常交给handler
综上所述:协程1234均为Job,协程234的父协程是协程1,协程1的父协程是SupervisorJob
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!