代码之家  ›  专栏  ›  技术社区  ›  Cristopher Bechtholdt

子作业不会取消Kotlin协同程序中的作用域

  •  0
  • Cristopher Bechtholdt  · 技术社区  · 3 年前

    我正在努力了解乔布斯的取消传播。我想如果一份工作被取消了,它的父亲也会被取消。

    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()
    
    }
    

    我得到下一个输出:

    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”不是也被取消了吗?

    我试着换成同样的语境

    1 回复  |  直到 3 年前
        1
  •  1
  •   Pawel    3 年前

    即使你在 cancellableScope2.launch 在此处启动时使用显式父作用域的作用域:

    cancellableScope2.launch {
    
        cancellableScope.launch {
            throw Error("1")
        }.join()
    
        cancellableScope.launch {
            println("2")
        }.join()
    
    }.join()
    

    这意味着这些工作是 cancellableScope 仅与无关 cancellableScope2 ,所以它们可以自由倒塌,而不会影响 scope2 。

    你可能会感到困惑的是 launch -ed作业不会返回任何结果。你知道 join 但这只是一个延迟,直到它们完成。他们是成功、失败还是被取消并不重要。

    但是,如果不是 发射 + 参加 您使用 async 和 await 你会得到你期望的行为。这创造了 Deferred 它确实返回了一个结果,所以在这种情况下 等候 会重新思考 Error(1) 它会倒塌 范围2 。