Kotlin 如何正确处理协同程序中的取消';什么是计算代码?

Kotlin 如何正确处理协同程序中的取消';什么是计算代码?,kotlin,kotlin-coroutines,Kotlin,Kotlin Coroutines,以下是我对协同程序取消的理解: 如果父协同程序被取消,子进程也将停止。如果 子协同程序抛出异常、同级和父协同程序 我会注意到并停止 除SupervisorJob外,即使其中一个 子协同程序已停止 所以,我写了一段代码来练习我的理解 代码片段1 fun main() { val parentScope = CoroutineScope(SupervisorJob()) parentScope.launch { val childJob = launch {

以下是我对协同程序取消的理解:

如果父协同程序被取消,子进程也将停止。如果 子协同程序抛出异常、同级和父协同程序 我会注意到并停止

除SupervisorJob外,即使其中一个 子协同程序已停止

所以,我写了一段代码来练习我的理解

代码片段1

fun main() {
    val parentScope = CoroutineScope(SupervisorJob())
    parentScope.launch {
        val childJob = launch {
            try {
                println("#1")
                Thread.sleep(1_000)
                println("#2")
            } catch (e: Exception) {
                println("#3")
            }
        }
        println("#4")
        childJob.cancel()
    }
    Thread.sleep(2_000)
}
以下是我的两个期望:

期望1:

#1 is called first because there's no blocking code between child and parent job.
#4 is called because `Thread.sleep` is blocking.
#3 is called because the childJob is cancelled, even though the coroutine is not finished.
期望2:

#4 is called first because the parent coroutine start first.
#1 is called because even though the childJob is cancelled, there's time for #1 to be executed.
但是,代码段1的实际输出是:

#4
#1
#2
我又读了一遍,发现对于计算代码,我们要么使用
屈服
,要么检查协同程序状态(
活动
取消
已完成
)。然后我进行以下调整:

代码片段2

fun main() {
    val parentScope = CoroutineScope(SupervisorJob())
    parentScope.launch {
        val childJob = launch {
            try {
                println("#1")
                Thread.sleep(1_000)
                if (isActive) {
                    println("#2")
                }
            } catch (e: Exception) {
                println("#3")
            }
        }
        println("#4")
        childJob.cancel()
    }
    Thread.sleep(2_000)
}
这一次的输出是:

#4
#1
以下是我的问题:

  • 在代码片段1中,取消
    childJob
    后#2如何仍然执行

  • 在代码片段1中,为什么即使调用了
    childJob
    也从不执行#3

  • 在代码片段2中,我们真的需要使用
    yield
    还是每次执行协同程序代码时都要检查协同程序状态?因为在我看来,代码将更难阅读

  • 我的代码片段或我对协同程序的理解是否有问题

  • 注意: 我不想对代码片段使用
    GlobalScope.runBlocking
    ,因为在实际项目中,我们无论如何都不使用
    GlobalScope
    。我想创建一个尽可能接近实际项目的示例,使用具有某种生命周期的父子范围

    在代码片段1中,在执行childJob之后,如何仍然执行#2 取消了

    只挂起函数。将
    线程睡眠(1_000)
    替换为挂起,它将被取消

    在代码片段1中,为什么即使childJob是 打电话

    那是因为联欢会没有取消。请参见第一个问题的答案

    在代码片段2中,我们真的需要使用yield还是checking 每次我们想要执行协同程序代码时,协同程序状态是什么? 因为在我看来,代码将更难阅读

    不,你不应该。每个挂起的函数都检查是否取消了协同路由

    我的代码片段或我的理解是否有问题 协同程序

    在使用协同程序时,了解挂起函数是非常重要的。文档部分对此进行了很好的解释。而且可能是有用的