与kotlins流异步发送流值

与kotlins流异步发送流值,kotlin,kotlin-coroutines,flow,Kotlin,Kotlin Coroutines,Flow,Iam使用kotlin和webflux构建了一个简单的Spring服务 我有一个返回流的端点。流包含的元素需要很长时间来计算,这是由延迟模拟的 它是这样构造的: suspend fun latest(): Flow<Message> { println("generating messages") return flow { for (i in 0..20) { println("generat

Iam使用kotlin和webflux构建了一个简单的Spring服务

我有一个返回流的端点。流包含的元素需要很长时间来计算,这是由
延迟模拟的

它是这样构造的:

suspend fun latest(): Flow<Message> {
    println("generating messages")


    return flow {
        for (i in 0..20) {
            println("generating $i")
            if (i % 2 == 0) delay(1000)
            else delay(200)
            println("generated messsage $i")
            emit(generateMessage(i))
        }
        println("messages generated")
    }
}
运行时,结果与预期一致

generating numbers
generating 2
generating 0
generating 1
generating 6
...
generated messsage 5 in 501ms
generated messsage 9 in 501ms
generated messsage 13 in 501ms
generated messsage 15 in 505ms
generated messsage 4 in 1004ms
...

您当前的方法对整个函数使用单个协程,包括
for
循环。这意味着对
suspend fun
的任何调用,例如
delay
将阻止整个协同路由,直到它完成。它确实释放了线程去做其他事情,但是当前的协程被阻塞了


根据您的简化示例,很难说什么是正确的解决方案。如果你真的想为每个for循环创建一个新的协程,你可以在那里启动它,但是从给出的信息来看,似乎不清楚这是一个正确的解决方案。

一旦你并行计算每个元素,你的第一个问题将是弄清楚什么时候所有的计算都完成了

你必须提前知道需要多少物品。因此,在我看来,构建一个简单的
列表
,然后等待所有延迟,然后返回整个内容是很自然的。在您的案例中,您不会从流中获得任何里程数,因为流都是关于在流集合中同步地做事情

您还可以将
channelFlow
与预期的已知消息计数结合使用,然后基于此终止流。这样做的好处是Spring可以更早地开始收集流量


编辑
实际上,计数的问题并不存在:流将自动等待您启动的所有子协同路由完成。

好的,但当我执行类似操作时,我将如何执行此操作:``返回流{withContext(Dispatchers.Default){启动{for(0..20中的i){emit(generateMessage(i))}println(“生成的数字”)}}}}``我在线程“main”中遇到异常IllegalStateException:违反了流不变量:我认为对流的限制是,您需要在调用函数的同一个协程上发出(类似于这样;异常会说明原因)。你必须使用类似的东西。同样,这很有可能不是正确的解决方案,但如果没有更多信息,我们将无法提供更多帮助。您还需要什么信息?我将尝试使用channelFlow并发布我的结果。不过,您不需要
Dispatchers.IO
。只需编写
launch{…}
,并且
latest()
不需要是挂起函数。
generating numbers
generating 2
generating 0
generating 1
generating 6
...
generated messsage 5 in 501ms
generated messsage 9 in 501ms
generated messsage 13 in 501ms
generated messsage 15 in 505ms
generated messsage 4 in 1004ms
...