我测试了阻塞代码和协程是如何交互的,以便于我自己理解。显然,我们应该使用非阻塞代码,但我想了解如果有一些阻塞代码在那里会发生什么。
如果我运行以下命令:
fun main() {
println("Start: ${Thread.currentThread()}")
runBlocking {
println("Run Blocking : ${Thread.currentThread()}")
launch(Dispatchers.D) { // Immediately scheduled for execution
println("Inside launch: ${Thread.currentThread()}")
}
Thread.sleep(10000)
println("Going to do some other stuff now")
}
println("Out of runBlocking")
}
所有的东西都在同一个协程中运行,Inside launch:
直到Thread.sleep
完成后才会出现。我认为这是因为它阻塞了,所以没有挂起,或者使用另一个协程。
如果我将Dispatchers.Default
传递给launch
(我以为launch默认使用Dispatchers.Default
,如果没有指定的话?),launch块将在一个单独的协程中运行并立即启动。
那么,为什么launch(Dispatchers.Default)
允许第二个协程启动,而launch
不允许呢?
1条答案
按热度按时间ruarlubt1#
我以为启动使用了Dispatchers。如果您没有指定一个,默认情况下是默认的
这就是您的错误之处。下面是documentation:
协程上下文是从CoroutineScope继承的。可以使用context参数指定其他上下文元素。如果上下文没有任何调度程序或任何其他ContinuationInterceptor,则使用Dispatchers.Default。
这意味着如果你没有给
launch
传递一个调度器,它将默认为launch
的上下文中的调度器,如果协程上下文没有调度器,* 那么 *launch
将使用Dispatchers.Default
。因此,在您的示例中,无参数的
launch
继承了上下文,从而继承了runBlocking
提供的调度程序,runBlocking
是一个单线程调度程序,运行在它阻塞的线程(这里是主线程)上。为什么
launch(Dispatchers.Default)
允许第二个协程启动,而launch
不允许呢?这是因为,正如我们刚刚看到的,这两种情况并不涉及相同的线程。对于
launch(Dispatchers.Default)
,启动的协程运行在一个单独的线程池中,并且可以与主线程池并行运行。然而,对于无参数的launch
,第二个协程与代码的其余部分运行在同一个线程中,因为它运行在runBlocking
的单线程调度器中。其由主线程支持。最后一块拼图是
Thread.sleep
是 * 阻塞 *(正如您所说的),不像delay
,它是协程库中的挂起等价物。(在无参数launch
的情况下),运行最后一个Thread.sleep
会阻塞主线程,并且永远不会给其他协程运行的机会。您需要一些东西来挂起执行,例如delay()
。