【问题标题】:Why can't kotlin coroutine be canceled?为什么不能取消kotlin协程?
【发布时间】:2021-10-01 08:31:52
【问题描述】:

我期望 (0, 1) 或 (0, 1, 2) 的结果,但不停止打印增加的数字。 我正在研究协程。我一直在照着这个例子,但我很好奇,所以我写了代码,发现了一些奇怪的东西。

class test {
    @Test
    fun test() = runBlocking {
        val startTime = System.currentTimeMillis()
        val job = launch {
            var nextTime = startTime
            var i = 0

            while (isActive) {
                if (System.currentTimeMillis() >= nextTime) {
                    println("${i++}")
                    nextTime += 500L
                }
            }
        }

        delay(1000L)
        println("[main]: tired for wait")
        job.cancelAndJoin()
        println("[main]: finish")
    }
}

---
0
1
2
3
4
5
6
...

但下面的代码按预期工作。

class test {
    @Test
    fun test() = runBlocking {
        val startTime = System.currentTimeMillis()
        val job = launch(Dispatchers.Default) {
            var nextTime = startTime
            var i = 0

            while (isActive) {
                if (System.currentTimeMillis() >= nextTime) {
                    println("${i++}")
                    nextTime += 500L
                }
            }
        }

        delay(1000L)
        println("[main]: tired for wait")
        job.cancelAndJoin()
        println("[main]: finish")
    }
}

----
0
1
2
[main]: tired for wait
[main]: finish

我只需添加Dispatchers.Default 即可启动。 为什么第一个代码没有按预期输出?

【问题讨论】:

  • 好吧,我首先将控制权交给循环内的操作系统,例如休眠 1 毫秒,否则你会吃掉整个处理器内核,因为那里有一个紧密的循环。 (即使它不一定与您的问题有关。)

标签: kotlin coroutine


【解决方案1】:

这是因为默认情况下runBlocking() 创建了一个单线程调度程序来调度协程。外部协程到达delay() 点,它挂起,然后内部协程开始执行,但它永远不会释放它的线程,因此外部协程无法恢复。并且因为外部协程永远不会恢复,所以它不能取消内部协程。

为避免此类问题,如果您需要执行非常长的计算,最好不时致电yield()。它可以释放线程以供其他协程使用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-04
    • 2021-11-12
    • 2021-10-02
    • 2017-03-15
    • 1970-01-01
    相关资源
    最近更新 更多