与kotlins流异步发送流值
Iam使用kotlin和webflux构建了一个简单的Spring服务 我有一个返回流的端点。流包含的元素需要很长时间来计算,这是由与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
延迟模拟的
它是这样构造的:
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
...