【问题标题】:NonCancellable coroutine gets cancelledNonCancellable 协程被取消
【发布时间】:2020-11-28 00:57:45
【问题描述】:

我正在尝试使用不可取消的协程,我编写了以下代码:

fun main(): Unit = runBlocking {
    // launch first coroutine
    coroutineScope {
        val job1 = launch {
            withContext(NonCancellable) {
                val delay = Random.nextLong(from = 500, until = 5000)
                println("Coroutine started. Waiting for ${delay}ms")
                delay(delay)
                println("Coroutine completed")
            }
        }

        delay(300) // let it print the first line
        println("Cancelling coroutine")
        job1.cancelAndJoin()
    }
}

输出:

Coroutine started. Waiting for 1313ms
Cancelling coroutine
Coroutine completed

到目前为止,一切都按预期进行。但是,如果我直接在launch 函数中传递NonCancellable 上下文(或者更确切地说是Job),则行为会发生变化并且协程会被取消:

fun main(): Unit = runBlocking {
    // launch first coroutine
    coroutineScope {
        val job1 = launch(context = NonCancellable) {
            val delay = Random.nextLong(from = 500, until = 5000)
            println("Coroutine started. Waiting for ${delay}ms")
            delay(delay)
            println("Coroutine completed")
        }

        delay(300) // let it print the first line
        println("Cancelling coroutine")
        job1.cancelAndJoin()
    }
}

输出:

Coroutine started. Waiting for 4996ms
Cancelling coroutine

为什么第二个 sn-p 会产生不同的输出?

【问题讨论】:

    标签: kotlin kotlin-coroutines


    【解决方案1】:

    您作为参数传递给launch 方法的作业不是启动的协程的作业,而是它的父作业

    在上面的第二个 sn-p 中,NonCancellablejob1 的父作业。由于job1 只是一个普通的工作,它是可以取消的(但它的父级不是)。

    【讨论】:

    • 感谢您的澄清!但是,那个家长工作的目的是什么?我的理解是launch 只允许创建 1 个协程,所以我看不出“容器”工作有什么用处。编辑:哦,也许我们可以在第二点添加额外的孩子,在这种情况下,“容器”会有一些实际用途。这是预期的目的吗?
    • 父作业通常用于强制执行结构化并发(例如,当父协程被取消时取消子协程)。传递给 launch 的作业用于中断隐式 结构化并发 - 您正在为协程显式选择新的父作业,而不是使用范围的作业你打电话给launch。就我个人而言,我从未使用过它——它更难推理,也更容易引入错误——有(总是?)更好的方法来做同样的事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-28
    • 2021-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多