Kotlin 协程是如何调度的

FRR*_*FRR 5 android kotlin kotlin-coroutines

我最近阅读了很多关于 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")
    }
}

Run Code Online (Sandbox Code Playgroud)

这个的输出是:

E/test: B
E/test: A
Run Code Online (Sandbox Code Playgroud)

我不明白这是怎么回事,我只使用一个线程(主线程)。如果我的代码按顺序执行,当我到达该行时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(".") }
}
Run Code Online (Sandbox Code Playgroud)

似乎按预期工作并打印: main @coroutine#1World!...........................

因为 1 thread == sequential work

希望我的问题有意义,感谢阅读!

Luk*_*rog 2

在底层,主调度程序使用 Handler 将 Runnable 发布到 MessageQueue。基本上,它\xe2\x80\x99将被添加到事件队列的末尾。这意味着它将很快执行,但不会立即执行。因此,为什么 \xe2\x80\x9cB\xe2\x80\x9d 在 \xe2\x80\x9cA\xe2\x80\x9d 之前打印。

\n\n

您可以在本文中找到更多信息。

\n\n

由OP编辑(在阅读本文之前阅读上面的文章):

\n\n

只是想澄清为什么上面的 android 示例运行良好,以防有人仍然想知道。

\n\n
fun main() {\n    GlobalScope.launch(Dispatchers.Unconfined) { // launch new coroutine in background and continue\n        print(Thread.currentThread().name + "World!") // print after delay\n    }\n    (0 .. 1000).forEach { print(".") }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我们正在设置GlobalScope使用UNCONFINED调度程序,并且该调度程序已isDispatchNeeded设置为false。\nfalse表示“在当前线程中调度”,这就是我们看到日志按顺序打印的原因。UNCONFINED不应该在常规代码中使用。

\n\n

所有其他调度程序都已isDispatchNeeded设置为trueUI 调度程序。请参阅: https: //kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-dispatcher/is-dispatch-needed.html

\n\n

Default(顺便说一句,如果我们不指定调度程序,则GlobalScope 使用调度程序)

\n