你的第一个协同线的医生说-
runBlocking
的名称意味着运行它的线程(在本例中是主线程)在调用期间被阻塞,直到runBlocking { ... }
中的所有协同线完成它们的执行。
运行runBlocking的线程阻塞是否正确?
如果主线程被阻塞了,那么在下面的代码(来自同一个文档)中,启动{}启动的协同线是如何在主线程上运行的呢??
import kotlinx.coroutines.*
fun main() = runBlocking { // this: CoroutineScope
launch { // launch a new coroutine and continue
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println(Thread.currentThread().name + " World!") // print after delay
}
println(Thread.currentThread().name + " Hello") // main coroutine continues while a previous one is delayed
}
我的理解是
以下是上述代码的输出-
main @coroutine#1 Hello
main @coroutine#2 World!
runBlocking文档中的相同问题
运行一个新的协同线,阻塞当前线程的,直到它完成为止。这一功能不应从协同线中使用。它旨在将常规的阻塞代码连接到以挂起方式编写的库中,用于主要函数和测试。
发布于 2022-09-17 15:10:21
比较您为runBlocking
发布的文档
运行一个新的协同线并阻塞当前线程,直到它完成为止。
在不阻塞当前线程的情况下启动新的协同线,并以作业的形式返回对协同线的引用。
它们都创建了一个新的协同线,只是launch
异步运行协同线,并允许调用方继续运行代码。runBlocking
不允许调用者继续运行,直到在该协同线中运行的所有操作完成为止。因此,runBlocking
并不控制协同线中的内容的行为,只控制调用runBlocking
的代码的执行。
对代码的这种调整可能会使事情变得更清楚:
fun main() {
runBlocking {
launch {
delay(1000L)
println(Thread.currentThread().name + " World!")
}
println(Thread.currentThread().name + " Hello")
}
// this -follows- the runBlocking statement
println("Hey I'm runnin' here!")
}
main @coroutine#1 Hello
main @coroutine#2 World!
Hey I'm runnin' here!
所以现在发生的是:
runBlocking
运行,阻塞主线程。下一行不会运行,直到这个协同线中的一切都完成!launch
运行,在同一个线程上创建一个新的协同线,但不阻塞它。下一行的代码将能够在运行时运行,因为它们位于单独的协同线中,但在短时间内轮流运行(因为它们位于同一个线程上)。这个协同线立即调用delay
,所以即使它在原始协同线中运行在行之前( launch)
后面的println
),它肯定会在很久之后到达自己的println
println
的launch
运行,因为这个协同线独立于另一个协同线。这个协同线已经完成(但另一个还在运行)println
its launch
在延迟后运行。这个协同线没有其他事可做,所以它也完成了runBlocking
发起的协同线中的所有runBlocking
都已经完成,所以阻塞协同线结束和执行可以在启动的范围内继续。println
终于要运行了!也只是为了澄清一个可能的误解:
运行runBlocking的线程阻塞是否正确? 如果主线程被阻塞,那么启动{}在下面的代码(来自同一个文档)中的coroutine是如何在主线程上运行的?
所有协同器都运行在与调用方相同的线程上,除非明确告诉它们不要运行,或者使用可以将它们移动到不同线程的调度程序。它只是协同“轮流”,并得到一些时间来执行一些线程上的代码。所以看起来他们在“同时”运行,即使他们不是。
因此,由于launch
不“阻塞”,这意味着调用它的协同线被允许继续,得到一些时间来执行其余的代码,而启动的协同线也有一些时隙。他们可以独立运行。
但是runBlocking
确实会阻塞,这意味着在它启动的协同线完成之前,它不会有任何执行时间。它需要休息直到协同线完成。所以它实际上不是阻塞主线程在正常意义上,否则线程上的任何协同线都不能运行!它只是在它自己的范围内阻止执行--这是一种表达“在这个工作完成之前这里不会发生其他事情”的方式。这就是为什么它是一个常见的main
函数包装器,它可以创建一个所有运行的协同工作的世界,并阻止main
函数完成和结束程序。但是做的阻止了运行之外的任何东西,这就是为什么在像安卓这样的系统中,除了你想运行的任何协同机制之外,还有其他东西在运行。
而且,launch
实际上运行在一个CoroutineScope
(即CoroutineScope.launch
)上,它可以在一个协同线中访问它--这就是为什么您必须在其中使用它!runBlocking
是一个独立的构建器函数,但是传入的函数块有一种CoroutineScope.() -> T
类型--也就是说,它将被传递到CoroutineScope
,就像框架提供的默认构造器。当它的所有子协同工作完成时,CoroutineScope
就是计算出来的,并通知调用者它已经完成了。runBlocking
只是等待这样的事情发生,而不是允许执行继续构建器。
发布于 2022-09-17 17:41:36
自从我发布了这个问题之后,我搜索了一个答案,并阅读了几篇文章和@cactustictacs的答案,我认为the current thread gets blocked
这个词让读者陷入了一种思维障碍,迫使他们认为这条线没有什么作用。
虽然coroutineScope
只是挂起,为其他用途释放底层线程,但runBlocking {...}
在等待它的身体和所有子协同器完成时,不会离开线程;这就是为什么它是一个正常的函数,而不是挂起的函数。由于所有子协同器都从runBlocking
继承相同的上下文(& dispatcher,除非传递另一个上下文),它们将在同一个线程上继续。所以是的,线程被阻塞,等待runBlocking完成,但实际上它正忙着执行runBlocking body及其所有子协同。
另外,来自runBlocking
的文档
这个构建器的默认CoroutineDispatcher是事件循环的内部实现,它在这个阻塞的线程中处理连续性,直到这个协同线完成为止。
底层runBlocking
的线程正忙于执行一个事件循环,该循环处理runBlocking主体及其所有子协同(那些从runBlocking继承上下文的子协同)。这里有一个漂亮的媒体文章解释了这个幻影事件循环将Kotlin合作伙伴关系学习为Java开发(第二部分)
因此,blocked thread
只是意味着线程忙于执行runBlocking
主体,除非所有runBlocking完成并启动,否则不会出现。
这和用简单的英语说的话一样--我被阻止研究这个话题,不会再做任何事情了,,除非我解开这个谜团并发布一个关于它的答案。
https://stackoverflow.com/questions/73755272
复制相似问题