kotlin - 为什么流程不执行,没有抛出错误?
问题描述
GlobalScope 或自定义 CoroutineScope 实例都不起作用:
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun makeFlow() = flow {
println("sending first value")
emit(1)
println("first value collected, sending another value")
emit(2)
println("second value collected, sending a third value")
emit(3)
println("done")
}
@InternalCoroutinesApi
fun main() {
val someScope = CoroutineScope(Dispatchers.Default)
someScope.launch {
makeFlow().collect { value ->
println("value is $value")
}
}
GlobalScope.launch {
makeFlow().collect { value ->
println("value is $value")
}
}
}
绝对没有输出或抛出错误
为什么?
更奇怪的是,当我添加一个runBlocking{}
块时,一切都会执行:
val someScope = CoroutineScope(Dispatchers.Default)
someScope.launch {
makeFlow().collect { value ->
println("someScope: value is $value")
}
}
GlobalScope.launch {
makeFlow().collect { value ->
println("GlobalScope: value is $value")
}
}
runBlocking {
makeFlow().collect { value ->
println("runBlocking: value is $value")
}
}
输出:
sending first value
sending first value
sending first value
runBlocking: value is 1
GlobalScope: value is 1
first value collected, sending another value
GlobalScope: value is 2
second value collected, sending a third value
GlobalScope: value is 3
done
someScope: value is 1
first value collected, sending another value
someScope: value is 2
second value collected, sending a third value
someScope: value is 3
done
first value collected, sending another value
runBlocking: value is 2
second value collected, sending a third value
runBlocking: value is 3
done
解决方案
您启动的协程没有完成,因为main
函数在触发它们后立即返回,而不等待它们,从而完成您的应用程序。没有发生错误,因为这是预期的行为。
runBlocking
的 lambda 将不会返回,直到其中的所有协程都返回。在这种情况下,它恰好浪费了足够的时间来让其他两个协程有时间完成,可能是因为它是最后启动的,并且完成的工作量大致相同。
如果您对前两个引入延迟,他们将没有机会完成:
fun main() {
val someScope = CoroutineScope(Dispatchers.Default)
someScope.launch {
delay(100L)
makeFlow().collect {
makeFlow().collect { value ->
println("value is $value")
}
}
}
GlobalScope.launch {
delay(100L)
makeFlow().collect { value ->
println("value is $value")
}
}
runBlocking {
makeFlow().collect { value ->
println("runBlocking: value is $value")
}
}
}
sending first value
runBlocking: value is 1
first value collected, sending another value
runBlocking: value is 2
second value collected, sending a third value
runBlocking: value is 3
done
推荐阅读
- .net - Is it possible to use ASP .Net Core 3.1 from a library that targets .NET Standard 2.x?
- javascript - Electron 未正确加载 index.html,本地文件夹中的文件未加载
- css - 如何使用 PostCss 编译 CSS 变量
- mysql - SQL 使用 WHERE 子句和来自多个表的 ALIASING 数据
- java - Java - 在除以双精度时无法将双精度转换为整数
- apache-spark - 如何优雅地停止 spark dStream 进程
- python - 基于可用参数的动态函数签名?
- google-app-engine - 为什么 Google App Engine 应用与 GCP 项目是一对一的?
- java - 将数据插入sqlite数据库后如何更新应用程序数据库
- c - 使用带有 TMS320F2812 的 TI CCS v3.3 如何在 DSP 的闪存和导出的 bin 文件中的特定地址定义特定数据?