如果协程遇到除CancellationException以外的异常,它将取消具有该异常的父对象.此行为不能被覆盖,并且用于为不依赖于CoroutineExceptionHandler实现的结构化并发提供稳定的协程层次结构.当父级的所有子级终止时,父级将处理原始异常.
If a coroutine encounters exception other than CancellationException, it cancels its parent with that exception. This behaviour cannot be overridden and is used to provide stable coroutines hierarchies for structured concurrency which do not depend on CoroutineExceptionHandler implementation. The original exception is handled by the parent when all its children terminate.
这也是为什么在这些示例中,CoroutineExceptionHandler始终安装到在GlobalScope中创建的协程的原因. 将异常处理程序安装到在主runBlocking范围内启动的协程中没有意义,因为尽管安装了该处理程序,但主协程将始终在其子进程完成异常时被取消 >.
This also a reason why, in these examples, CoroutineExceptionHandler is always installed to a coroutine that is created in GlobalScope. It does not make sense to install an exception handler to a coroutine that is launched in the scope of the main runBlocking, since the main coroutine is going to be always cancelled when its child completes with exception despite the installed handler.
(重点是我的)
这里描述的内容不仅适用于runBlocking
和GlobalScope
,而且还适用于任何非顶级协程生成器和自定义范围.
What's described here applies not just to runBlocking
and GlobalScope
, but any non-top-level coroutine builder and custom scope.
要进行说明(使用kotlinx.coroutines v1.0.0):
To illustrate (using kotlinx.coroutines v1.0.0):
fun f() = runBlocking {
val h1 = CoroutineExceptionHandler { _, e ->
trace("handler 1 e: $e")
}
val h2 = CoroutineExceptionHandler { _, e ->
trace("handler 2 e: $e")
}
val cs = CoroutineScope(newSingleThreadContext("t1"))
trace("launching j1")
val j1 = cs.launch(h1) {
delay(1000)
trace("launching j2")
val j2 = launch(h2) {
delay(500)
trace("throwing exception")
throw RuntimeException("error!")
}
j2.join()
}
trace("joining j1")
j1.join()
trace("exiting f")
}
f()
输出:
[main @coroutine#1]: launching j1
[main @coroutine#1]: joining j1
[t1 @coroutine#2]: launching j2
[t1 @coroutine#3]: throwing exception
[t1 @coroutine#2]: handler 1 e: java.lang.RuntimeException: error!
[main @coroutine#1]: exiting f
请注意,已执行处理程序h1
,但未执行.这类似于GlobalScope#launch
执行时的处理程序,但不是提供给runBlocking
内部任何launch
的处理程序.
Note that handler h1
is executed, but h2
isn't. This is analogous to the handler on GlobalScope#launch
executing, but not the handler provided to any launch
inside runBlocking
.
TLDR
提供给范围的非根协程的处理程序将被忽略.提供给根协程的处理程序将被执行.
正如Marko Topolnik在下面的注释中正确指出的那样,以上概括仅适用于launch
创建的协程.由async
或produce
创建的代码将始终忽略所有处理程序.
As correctly pointed out by Marko Topolnik in the comments below, the above generalization only applies to coroutines created by launch
. Those created by async
or produce
will always ignore all handlers.
这篇关于作为启动上下文提供时,CoroutineExceptionHandler不执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!