最近,我一直在阅读很多文章,并观看了很多关于Kotlin协同例程的视频,尽管我付出了很多努力,但我仍然无法理解它们。
我想我终于找到了一种方法来说明我的问题:
class MyViewModel() : CoroutineScope {
override val coroutineContext = Dispatchers.Main + Job()
fun foo() = launch(handler) {
Log.e("test", "A")
}
}
class MainActivity : Activity() {
override fun onCreate() {
MainViewModel().foo()
Log.e("test", "B")
}
}
此输出为:
E/test: B
E/test: A
我不知道怎么回事,我只使用一个线程(主线程)。如果我的代码按顺序执行,那么到到达行log(B)
... log(A)
时,应该已经打印了。
协程库是否在内部使用其他线程来完成此任务?这是我能提出的唯一解释,但在文档中没有找到任何说明。
PS:很抱歉将android
投进混音中,但代码如下:
fun main() {
GlobalScope.launch(Dispatchers.Unconfined) { // launch new coroutine in background and continue
print(Thread.currentThread().name + "World!") // print after delay
}
(0 .. 1000).forEach { print(".") }
}
似乎可以正常工作并打印:
main @coroutine#1World!...........................
因为1 thread == sequential work
希望我的问题有意义,感谢您的阅读!
答案 0 :(得分:2)
在后台,主调度程序使用Handler将Runnable发布到MessageQueue。基本上,它将被添加到事件队列的末尾。这意味着它将很快执行,但不会立即执行。因此,为什么在“ A”之前打印“ B”。
您可以在this article中找到更多信息。
由OP进行编辑(请先阅读上面的文章,然后再阅读):
只是想弄清楚为什么上面的android示例可以正常工作,以防万一有人还在疑惑。
fun main() {
GlobalScope.launch(Dispatchers.Unconfined) { // launch new coroutine in background and continue
print(Thread.currentThread().name + "World!") // print after delay
}
(0 .. 1000).forEach { print(".") }
}
我们正在将GlobalScope
设置为使用UNCONFINED
调度程序,并且该调度程序已将isDispatchNeeded
设置为false
。
false
的意思是“当前线程中的计划”,这就是为什么我们看到日志按顺序打印的原因。 UNCONFINED
不应在常规代码中使用。
所有其他调度程序甚至UI调度程序都将isDispatchNeeded
设置为true
。参见:https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/is-dispatch-needed.html
(如果未指定,btw GlobalScope将使用Default
调度程序)