我有以下使用协程的Kotlin代码片段,我对输出感到困惑.谁能解释一下为什么这两种情况的输出都是"A、B"?

// Code Snippet 1
fun main() {
  CoroutineScope(Dispatchers.IO).launch { 
        print("A")
    }
    print("B")
}

输出:AB

// Code Snippet 2
fun main() {
    CoroutineScope(Dispatchers.IO).launch { 
        delay(200)
        print("A")
    }
    print("B")
}

输出AB

我已经在Kotlin操场(LINK-kotlin playground)上运行了这段代码 我不能理解为什么在添加了200ms的延迟之后,A打印在B之前

推荐答案

有意思的.我预计至少第二个 case 将只打印B,因为程序在A有机会打印之前终止.这实际上是我在IDE中运行您的代码时得到的结果.

你的playground链接使用的是println,而不是print,但却在同一行上输出了这个奇怪的A B.这可能是Kotlin playground在从不同线程输出时的stdout处理中的一个错误.我想不要相信操场上的并发输出.

编辑:我确认,操场收到的有效负载包含"text": "A\n<outStream>B\n</outStream>",这似乎解释了并发输出显示不佳的原因(这里只有主线程的输出包含在<outStream>中).

撇开这个错误不谈,您应该注意到,您不会等待以任何方式在这里启动的协程.这意味着任何执行顺序在技术上都是可能的:主体可以在启动的协程执行之前或之后打印B,程序甚至可以在启动的协程执行或结束之前终止.

在等待其他协程完成时,您可以在结尾处使用Thread.sleep()来阻塞主线程,但这并不适合协程.

如果您希望自动等待协程完成,则应使用 struct 化并发(例如,此处使用runBlockingsuspend fun main()+coroutineScope):

fun main(): Unit = runBlocking {
    launch(Dispatchers.IO) {
        delay(200)
        println("A")
    }
    println("B")
}

在返回之前,runBlocking将自动等待子协程结束,因此您的主线程将被阻止,等待A被打印,这将防止程序过早终止.

Kotlin相关问答推荐

文本正在被切断在200%的屏幕比例在Jetpack Compose

将基于注册的服务转换为流

为什么Kotlin函数参数名会 destruct 方法调用?

从 Kotlin 的父类获取函数注解

使用调度程序运行异步 Kotlin 代码

如何在 Kotlin 中将with代码转换为完整代码?

在 kotlin 中重载函数时,我在一些非常基本的代码上不断收到类型不匹配

is return inside function definition 也是 kotlin 中的表达式

Kotlin - 当表达式返回函数类型

如果我可以将 Flow 和 StateFlow 与生命周期范围 \ viewLifecycleOwner.lifecycleScope 一起使用,那么在 ViewModel 中使用 LiveData 有什么意义

在Kotlin中不带类直接引用枚举实例

Kotlin:使用Gradle进行增量编译

从片段(fragment)中的点击事件启动协同程序

Kotlin的BiMap/2-way hashmap

项目未与 Gradle 链接

Kotlin 中更好的回调方法是什么?侦听器与高阶函数

如何在Kotlin中使方法param可变?

Kotlin 与 C# 中的标志枚举变量具有相似效果的方式是什么

uses-sdk:minSdkVersion 16 不能小于库中声明的版本 23

Kotlin-将UTC转换为当地时间