英文:
Child Jobs don't cancell scope in Kotlin coroutines
问题
我正在尝试了解有关作业(Jobs)中的取消传播的信息。我认为如果一个作业被取消了,它的父作业也会被取消。
val cancellableScope = CoroutineScope(Dispatchers.Default + Job())
val cancellableScope2 = CoroutineScope(Dispatchers.Default + Job())
runBlocking {
cancellableScope2.launch {
cancellableScope.launch {
throw Error("1")
}.join()
cancellableScope.launch {
println("2")
}.join()
}.join()
cancellableScope2.launch {
delay(200)
println("3")
}.join()
}
我得到了以下输出:
Exception in thread "DefaultDispatcher-worker-2" java.lang.Error: 1
at MainKt$main$1$1$1.invokeSuspend(Main.kt:21)
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:584)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@430de60, Dispatchers.Default]
3
我期望只会得到错误信息,但也打印出了 "3"。难道不是当第一个启动失败时,“cancellableScope2” 也会被取消吗?
我尝试改成相同的上下文。
英文:
I'm trying to learn about cancel propagation in Jobs. I thought if a Job get's cancelled, its father too.
val cancellableScope = CoroutineScope(Dispatchers.Default + Job())
val cancellableScope2 = CoroutineScope(Dispatchers.Default + Job())
runBlocking {
cancellableScope2.launch {
cancellableScope.launch {
throw Error("1")
}.join()
cancellableScope.launch {
println("2")
}.join()
}.join()
cancellableScope2.launch {
delay(200)
println("llegó 3")
}.join()
}
I get the next output:
Exception in thread "DefaultDispatcher-worker-2" java.lang.Error: 1
at MainKt$main$1$1$1.invokeSuspend(Main.kt:21)
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:584)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697)
at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)
Suppressed: kotlinx.coroutines.internal.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}@430de60, Dispatchers.Default]
3
I expected to only get the error, but "3" get's printed too. Isn't "cancellableScope2" cancelled when first launched fails too?
I tried changing to the same context
答案1
得分: 1
尽管您在cancellableScope2.launch范围中启动,但在此处启动时使用了显式的父范围:
cancellableScope2.launch {
cancellableScope.launch {
throw Error("1")
}.join()
cancellableScope.launch {
println("2")
}.join()
}.join()
这意味着这些作业仅是cancellableScope的子孙作业,与cancellableScope2没有关系,因此它们可以自由地崩溃,而不会影响scope2的状态。
您可能会感到困惑的是launch启动的作业不会返回任何结果。您在它们上面执行join,但这只是等待它们完成。它们成功、失败或被取消都无关紧要。
但是,如果您使用 async 和 await 而不是 launch + join,您将获得您期望的行为。这会创建一个返回结果的 Deferred,因此在这种情况下,await 将重新抛出 Error(1),从而会崩溃 scope2。
英文:
Even though you're in cancellableScope2.launch scope you use explicit parent scope when launching here:
cancellableScope2.launch {
cancellableScope.launch {
throw Error("1")
}.join()
cancellableScope.launch {
println("2")
}.join()
}.join()
That means those jobs are descendant of cancellableScope only and have no relation to cancellableScope2, so they are free to collapse without affecting state of scope2.
The thing you might be confused about is that launch-ed jobs don't return any result. You do join on them but it's just a delay until they're complete. Whether they succeed, fail or get cancelled doesn't matter.
However if instead of launch + join you use async and await you'll get the behavior you expect. That creates a Deferred which does return a result so in this case await would rethrow Error(1) which will collapse scope2.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论