我对 runBlocking() 和 coroutineScope() 感到困惑。我已经读了很多这方面的内容,但我仍然感到困惑。我知道 runBlocking() 会阻塞线程,而 coroutineScope() 会挂起协程,但我不清楚这意味着什么。
在此示例中,它打印 A,然后打印 B。但是,runBlocking() 应该阻塞线程,直到所有代码完成。因此,当线程被 runBlocking() 阻塞时,不应打印 A。它应该打印 B,然后打印 A。
runBlocking {
launch {
delay(1000L)
println("A")
}
runBlocking {
delay(3000L)
println("B")
}
}
在这段代码中,它先打印 B,然后打印 A。
runBlocking {
launch {
delay(1000L)
println("A")
}
runBlocking {
Thread.sleep(3000L)
println("B")
}
}
Thread.sleep() 确实阻塞了线程,并且线程被阻塞时无法打印 A。
如果线程被阻塞时可以执行该线程中的协程,那么使用 runBlocking() 来阻塞线程意味着什么?
如果此代码与第一个代码具有相同的行为,那么 runBlocking() 和 coroutineScope() 有什么区别?
runBlocking {
launch {
delay(1000L)
println("A")
}
coroutineScope {
delay(3000L)
println("B")
}
}
我真的不知道为什么你的第一个示例没有按照 runBlocking 文档 似乎表明的方式工作。当我尝试时,它不是先打印“A”,而是根本不打印“A”!也许,正如其他人所说,这是因为 runBlocking 不应该从协程内运行(但这不是禁止的,否则应该抛出异常,并且该行为不应该违反文档)。
但是,这可能会解答您的问题。我重新实现了您的示例,没有外部
runBlocking
,使用 lifecycleScope.launch()
作为“A”协程(您也可以使用 GlobalScope.launch()
):
private fun testCoroutines() {
Log.d(TAG, "start on thread ${Thread.currentThread().name}")
this.lifecycleScope.launch(Dispatchers.Main) {
Log.d(TAG, "A in launch: ${threadAndJob()}")
delay(1000L)
Log.d(TAG, "A end launch: ${threadAndJob()}")
}
runBlocking {
Log.d(TAG, "B in runBlocking: ${threadAndJob()}")
delay(3000L)
Log.d(TAG, "B end runBlocking: ${threadAndJob()}")
}
Log.d(TAG, "finish on thread ${Thread.currentThread().name}")
}
private fun CoroutineScope.threadAndJob() =
"thread ${Thread.currentThread().name}; job ${coroutineContext.job}"
现在我们应该能够看到另一个协程是否可以在主线程上运行,而
runBlocking
应该阻止它。
我们可以在协程中不使用 runBlocking
来完成此操作。
输出:
start on thread main
B in runBlocking: thread main; job BlockingCoroutine{Active}@9b89588
B end runBlocking: thread main; job BlockingCoroutine{Active}@9b89588
finish on thread main
A in launch: thread main; job StandaloneCoroutine{Active}@a953b46
A end launch: thread main; job StandaloneCoroutine{Active}@a953b46
此日志输出向我们显示,即使
runBlocking
内部的 B 协程被挂起 3 秒,但在主线程上启动的 A 协程直到 runBlocking
代码完成后才能运行。这证实了主线程在 runBlocking
期间确实被阻塞,正如您从 runBlocking 文档中了解到的那样。
使用 runBlocking 的整个想法是,当您需要立即执行
runblocking
线程中的代码时,当您调用 runblocking
时:这意味着当您调用 a 时“阻塞,直到该块内的任何内容完成”父 runblocking
它只会阻塞,直到执行其中的代码,但在 coroutinescope
的情况下,您始终可以将其映射到特定的线程模式。我建议你先了解一下协程的基础知识!