为什么这些协程没有给出预期的输出?

Why do these coroutines not give the expected output?

我想了解 Kotlin 中的协程,但遇到了一些障碍。在下面的示例中,我希望发生以下情况:

但是它打印了这个:

0
3
2
1
4
5
6

我真的不明白为什么会这样。我主要不明白 job2 的输出怎么会出现在 4 之前。我很困惑。

println("0")
runBlocking {
    val job = GlobalScope.launch {
        // launch new coroutine and keep a reference to its Job
        delay(1200L)
        println("1")
    }
    val job2 = GlobalScope.launch {
        // launch new coroutine and keep a reference to its Job
        delay(1000L)
        println("2")
    }

    println("3")
    job.join() // wait until child coroutine completes
    println("4")
    job2.join() // wait until child coroutine
    println("5")
}
println("6")

正在阅读 documentation of kotlinx.coroutines#launch

By default, the coroutine is immediately scheduled for execution. Other start options can be specified via start parameter. See CoroutineStart for details. An optional start parameter can be set to CoroutineStart.LAZY to start coroutine lazily. In this case, the coroutine Job is created in new state. It can be explicitly started with start function and will be started implicitly on the first invocation of join.

因此您的协程在 launch 命令后立即启动。这应该解释执行命令的顺序。当主线程执行下一条语句时,异步协程中的 delay 会立即执行。 32 之前 1。然后等到第一个作业完成(打印 1),然后再从主线程打印 4

如果您希望代码按预期执行,您可以将 start = CoroutineStart.LAZY 参数添加到 launch,如下所示:

println("0")
runBlocking {
    val job = GlobalScope.launch(start = CoroutineStart.LAZY) {
        // launch new coroutine and keep a reference to its Job
        delay(1200L)
        println("1")
    }
    val job2 = GlobalScope.launch(start = CoroutineStart.LAZY) {
        // launch new coroutine and keep a reference to its Job
        delay(1000L)
        println("2")
    }

    println("3")
    job.join() // wait until child coroutine completes
    println("4")
    job2.join() // wait until child coroutine
    println("5")
}
println("6")

事情是这样的:

  1. 打印 0
  2. 输入runBlocking,阻塞当前线程,直到阻塞完成。
  3. 设置和launch job 1;作业立即开始执行,并被延迟语句暂停1200ms。
  4. 设置并启动作业 2;该作业立即开始执行,并通过延迟语句暂停 1000m。
  5. 打印 3
  6. 等待(暂停执行)直到作业 1 完成 (job.join())。
  7. 1000 毫秒后作业 2 打印 2 并完成
  8. 1200 毫秒后作业 1 打印 1 并完成
  9. 打印 4(因为作业 1 已完成)
  10. 等待(暂停执行)直到作业 2 完成 (job2.join())。这 returns 立即执行,因为作业 2 已经完成。
  11. 打印 5
  12. 打印 6,在 runBlocking 块完成并且它开始的线程继续后。

你可以阅读https://kotlinlang.org/docs/reference/coroutines/composing-suspending-functions.html to get a better insight into suspending functions. What helped me understand coroutines was this video: https://www.youtube.com/watch?v=_hfBv0a09Jc