捕获 Kotlin 异步协程中的异常并停止传播

Jay*_*Lee 6 asynchronous kotlin kotlin-coroutines

我想捕获异步协程引发的异常。下面的代码演示了一个问题:

import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
    try {
        println(failedConcurrentSum())
    } catch (e: ArithmeticException) {
        println("Computation failed with ArithmeticException")
    }
}

suspend fun failedConcurrentSum() = coroutineScope {
    try {
        val one = async {
            try {
                delay(1000L)
                42
            } finally {
                println("First child was cancelled")
            }
        }

        val two = async<Int> {
            println("Second child throws an exception")
            throw ArithmeticException()
        }

        one.await() + two.await()
    } catch (e: ArithmeticException) {
        println("Using a default value...")
        0
    }
}
Run Code Online (Sandbox Code Playgroud)

这打印:

Second child throws an exception
First child was cancelled
Computation failed with ArithmeticException
Run Code Online (Sandbox Code Playgroud)

内部try-catchfailedConcurrentSum处理 抛出的异常val two。我可以说服自己,这是由于“结构化并发”。

但是,这并不能解释为什么将async' 包裹在 a 中coroutineScope会捕获异常:

Second child throws an exception
First child was cancelled
Computation failed with ArithmeticException
Run Code Online (Sandbox Code Playgroud)

这打印:

First child was cancelled
Second child throws an exception
Using a default value...
0
Run Code Online (Sandbox Code Playgroud)

为什么后者捕获异常而第一个却没有?

IR4*_*R42 2

coroutineScope用途Job

\n\n
\n

默认情况下,任何作业\xe2\x80\x99s 子作业的失败都会导致其父作业立即失败并取消其其余子作业。\n 作业

\n
\n\n

您可以使用supervisorScope代替coroutineScope

\n\n
\n

子项失败或取消不会导致主管作业失败,也不会影响其其他子项。\n SupervisorJob

\n
\n\n

但你必须等待第一个块完成async

\n\n

使用coroutineScopeinsidetry catch发生异常时立即返回默认值

\n\n
suspend fun failedConcurrentSum() = try {\n    coroutineScope {\n        val one = async {\n            try {\n                delay(1000L)\n                42\n            } finally {\n                println("First child was cancelled")\n            }\n        }\n\n        val two = async<Int> {\n            println("Second child throws an exception")\n            throw ArithmeticException()\n        }\n\n        one.await() + two.await()\n    }\n} catch (e: ArithmeticException) {\n    println("Using a default value...")\n    0\n}\n
Run Code Online (Sandbox Code Playgroud)\n