[英]Kotlin async in coroutine: exception caught and still propagated?
I am running a coroutine in a SupervisorJob
with a try/catch block surrounding only the await calls.我在SupervisorJob
中运行一个协程,其中一个 try/catch 块仅围绕 await 调用。 The exception from the async block gets caught by the try/catch, but it still gets propagated and the app crashes.来自异步块的异常被 try/catch 捕获,但它仍然被传播并且应用程序崩溃。
This is what I have:这就是我所拥有的:
CoroutineScope(Dispatchers.IO + SupervisorJob()).launch {
val a = async {
delay(500)
throw Exception("excep a")
2
}
val b = async {
delay(500)
3
}
try {
println(a.await() + b.await())
} catch (e: Exception) {
println("exception: ${e.message}")
}
}
This is what I get (note that "excep a" gets caught):这是我得到的(注意“excep a”被捕获):
exception: excep a
Exception in thread "DefaultDispatcher-worker-3 @coroutine#1" java.lang.Exception: excep a
at com.example.app.AuthTest$co2$1$a$1.invokeSuspend(AuthTest.kt:314)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:750)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665)
The exception handling mechanism of supervisorJob and Job is not the same. supervisorJob 和 Job 的异常处理机制是不一样的。 For supervisory tasks, the transmission of exceptions can only be from the parent scope to the child scope, and the propagation direction of the exception is one-way.对于supervisor任务,异常的传输只能是从父scope到子scope,异常的传播方向是单向的。 Therefore, it is necessary to handle exceptions by itself for monitoring the scope of opening the coroutine.因此需要自行处理异常,以监控scope开启协程。
CoroutineScope(Dispatchers.IO + SupervisorJob()).launch(CoroutineExceptionHandler { _, throwable ->
println("$throwable")
}) {
val a = async {
delay(500)
throw Exception("excep a")
2
}
val b = async {
delay(500)
3
}
println(a.await() + b.await())
}
This exception will be handled in the top-level Job此异常将在顶层 Job 中处理
You are creating a parent coroutine using launch builder having IO dispatcher and SupervisorJob .您正在使用具有IO调度程序和SupervisorJob的启动构建器创建父协程。 Then you are creating two children coroutines using async biulder.然后,您将使用async biulder 创建两个子协程。 But remember the child coroutines do not inherit the Job from its parent.但请记住,子协程不会从其父协程继承 Job。 Each child coroutine creates their own Job.每个子协程创建自己的 Job。 So to avoid app crashing and exception apply the same supervisorjob explicitly to each child as shown below.因此,为避免应用程序崩溃和异常,将相同的 supervisorjob 明确应用于每个孩子,如下所示。
val supervisorJob = SupervisorJob()
CoroutineScope(Dispatchers.IO).launch {
val a = async(supervisorJob) {
delay(500)
throw Exception("excep a")
2
}
val b = async(supervisorJob) {
delay(500)
3
}
try {
println(a.await() + b.await())
} catch (e: Exception) {
println("exception: ${e.message}")
}
}
Thank you.谢谢你。
SupervisorJob
has launch
as Top coroutine and both async/await
are nested coroutines. SupervisorJob
已作为 Top 协程launch
,并且async/await
都是嵌套协程。
Nested async/await
always propagated up via Job hierarchy even if you use try/catch.嵌套的async/await
始终通过作业层次结构向上传播,即使您使用 try/catch。
launch
as Top coroutine require CoroutineExceptionHandler.作为 Top 协程launch
需要 CoroutineExceptionHandler。
Alternatively you can:或者你可以:
async
and try/catch
in supervisorScope
在supervisorScope
中包装async
和try/catch
async
and try/catch
in coroutineScope
inside try/catch
.将async
和try/catch
包装在try/catch
/catch 内的coroutineScope
中。 But in this case second async
will be cancelled after exception is thrown但在这种情况下,第二个async
将在抛出异常后被取消
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.