为什么Kotlin协程会阻止此代码?

问题描述

为什么此代码永远不会打印Hello World?

runBlocking(dispatchers.Main) {
    launch {
        delay(1)
        println("Hello world")
    }
}

但这会打印

runBlocking {
    launch {
        delay(1)
        println("Hello world")
    }
}

解决方法

在我看到的第一个示例中,该应用程序完全冻结了(当在按钮单击侦听器中使用时)。

问题是您造成了僵局:

  1. Dispatchers.Main通过将协程发布(调度)到主应用程序循环器中来工作
  2. runBlocking阻止主应用程序线程
  3. 主循环程序永远不会运行已发布的协程,因为它正在等待runBlocking完成

您可以使用Dispatchers.Main.immediate来稍微缓解“问题”,它是基本调度程序的一个更聪明的版本-如果它已经在主线程上运行并在其中执行,它不会将协程发布到主循环程序中-地方。

这将允许您运行launch块,但是delay将再次发布协程以继续在主循环程序上执行并导致另一个死锁。

第二个代码示例没有问题,因为在那里运行的协程不与主线程进行交互(除了runBlocking之外)。