【问题标题】:Why is exception handled by the handler of a non-root, non-supervisor coroutine?为什么异常由非根、非主管协程的处理程序处理?
【发布时间】:2022-12-24 05:59:42
【问题描述】:

我正在用这个测试函数测试协程的异常处理机制:

suspend fun test(){
    supervisorScope {launch(createExceptionHandler(1)) {
        coroutineScope {launch(createExceptionHandler(2)) {
            supervisorScope {launch { //SUPERVISOR WITH NO HANDLER
                coroutineScope {launch(createExceptionHandler(4)) {
                    coroutineScope {launch(createExceptionHandler(5)) {
                        throw Exception("Testing")
                    }}
                }}
            }}
        }}
    }}
}

fun createExceptionHandler(i: Int) = CoroutineExceptionHandler { _, throwable ->
    "---> exception handler #$i caught: ${throwable}".log()
}

结果:

---> exception handler #2 caught: java.lang.Exception: Testing

我原以为处理程序 #1 会捕获异常,令我惊讶的是,处理程序 #2 捕获了它!


阅读 docs,我希望处理程序 #2、#4、#5 被完全忽略:

...特别是,所有子协程(在另一个作业的上下文中创建的协程)将异常处理委托给它们的父协程,父协程也委托给父协程,依此类推直到根,所以 CoroutineExceptionHandler 安装在它们的上下文中从未使用过。

我的理解是异常在到达根时停止传播,或者主管范围带有异常处理程序。所以我认为处理程序 #1 会处理异常。

这个测试函数 (2) 似乎证实了我的信念:

suspend fun test2(){
    supervisorScope {launch(createExceptionHandler(1)) {
        supervisorScope {launch(createExceptionHandler(2)) {
            supervisorScope {launch {
                supervisorScope {launch {
                    supervisorScope {launch {
                        throw Exception("Testing")
                    }}
                }}
            }}
        }}
    }}
}

结果:

---> exception handler #2 caught: java.lang.Exception: Testing

我已经在线阅读了许多关于异常传播和处理的指南,但我非常坚持这一点......

任何线索都会有所帮助,感谢阅读!

【问题讨论】:

    标签: android kotlin kotlin-coroutines kotlin-multiplatform kotlin-multiplatform-mobile


    【解决方案1】:

    在您的第一个示例中,supervisorScope 在没有异常处理程序的情况下启动协程实际上是从外部范围继承异常处理程序。您可以通过在launch 之后打印CoroutineContext 来验证。

    【讨论】:

      【解决方案2】:

      launchsupervisorScope 中没有CoroutineExceptionHandler 是顶级launch 并且它从#2 继承了CoroutineExceptionHandler。协程中带有 launch 的异常会将异常传播给父级(如果可能)或将其传递给异常处理程序。 supervisorScope 没有传播,因此崩溃的启动协程将其未捕获的异常传递给继承的 CoroutineExceptionHandler。有关 CoroutineExceptionHandler 继承的更多详细信息:elizarov.medium.com/coroutine-context-and-scope-c8b255d59055

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-17
        • 1970-01-01
        • 1970-01-01
        • 2016-01-10
        • 1970-01-01
        • 2021-10-14
        相关资源
        最近更新 更多