Kotlin 如何使用协同流程删除\u最新版本<;T>;?

Kotlin 如何使用协同流程删除\u最新版本<;T>;?,kotlin,kotlin-coroutines,kotlin-coroutines-flow,Kotlin,Kotlin Coroutines,Kotlin Coroutines Flow,请帮忙。我试图做到: 2sec 2sec 2sec ------[A]------[B]------[C]------...----------------> InitailFlow \ | | \ drop drop \ 5sec \ 5sec 5sec ----------[1]---------[2]---------[3]-----

请帮忙。我试图做到:

    2sec     2sec     2sec
------[A]------[B]------[C]------...----------------> InitailFlow
       \        |        | 
        \      drop      drop
         \
     5sec \    5sec        5sec
----------[1]---------[2]---------[3]-----|> AnotherFlow
result: [A1, A2, A3]
所以我有一个InitailFlow,它发出一个短时间(2秒),然后转换成另一个需要更长时间才能完成的流(总共15秒)。。。我想在另一个流未完成时删除InitialFlow发出的其他传入项

我试过:

flow{
    delay(2000)
    emit("A")
    delay(2000)
    emit("B")
    delay(2000)
    emit("C")
}.buffer(0, BufferOverflow.DROP_LATEST)
    .onEach {
       println("Event for $it")
    }
    .flatMapConcat {
       flow {
           delay(5000)
           emit("${it}1")
           delay(5000)
           emit("${it}2")
           delay(5000)
           emit("${it}3")
        }
     }
     .onEach {
         println(it)
     }
     .launchIn(scope)
但出于某种原因,这就是结果:

Event for A
A1
A2
A3
Event for B
B1
B2
B3
即使我有一个
.buffer(0,BufferOverflow.DROP\u LATEST)
,它仍会出于某种原因处理
事件B

为什么它仍然处理事件B

有办法做到这一点吗?我预计输出仅为:

Event for A
A1
A2
A3

提前感谢。

每次调用
emit
时,它都会被挂起,因此
缓冲区
操作符无效

我不确定您希望得到的输出,但我认为您正在寻找
合并
运算符:

flow{
    delay(2000)
    emit("A")
    delay(2000)
    emit("B")
    delay(2000)
    emit("C")
}
.conflate()
.onEach {
    println("Event for $it")
}
.flatMapConcat {
    flow {
        delay(5000)
        emit("${it}1")
        delay(5000)
        emit("${it}2")
        delay(5000)
        emit("${it}3")
    }
}
.onEach {
    println(it)
}
.launchIn(scope)
合并
运营商官方文档说明:

通过合并通道合并流量排放,并在 单独的协同程序。这样做的效果是,发射器永远不会消失 由于收集器速度慢而挂起,但收集器总是获得最多 最近的排放值


您可以找到
合并的
操作员官方文档。

这应该适合您:

fun <T> Flow<T>.dropIfBusy(): Flow<T> = flow {
    coroutineScope {
        val channel = produce(capacity = Channel.RENDEZVOUS) {
            collect { offer(it) }
        }
        channel.consumeEach { emit(it) }
    }
}
fun Flow.dropIfBusy():Flow=Flow{
共线镜{
val通道=生产(容量=通道集合){
收集{offer(it)}
}
channel.consumereach{emit(it)}
}
}
这基本上是从
这里唯一的区别是我们使用
channel.offer
而不是
channel.send

当与会合频道一起使用时,所有提供给该频道的值都会在暂停时被删除,从而创建您想要的行为。

在使用@AdrianK的解决方案一段时间后,我实际上找到了一个使用
channelFlow
的更简单的解决方案。由于
channelFlow
目前是实验性API,您必须选择使用它

像这样:

fun <T> Flow<T>.dropIfBusy(): Flow<T> = channelFlow {
    collect { offer(it) }
}.buffer(0)
fun Flow.dropIfBusy():Flow=channelFlow{
收集{offer(it)}
}.缓冲区(0)

您使用的是哪个协同程序版本?我相信我使用的是最新版本,但我找不到
.buffer(0,BufferOverflow.DROP\u latest)
函数…@Deadbeef它是在1.4.0中添加的,我没有真正得到您所期望的输出。你能举一个你想要的输出的例子吗?@deadbeefits1.4.0-M1@marstran当然我添加了预期的输出。。。它的输出也与我问题中的“图形”相同。。所以我想再澄清一点。。。我希望,只要
flatMap
中的othr流程尚未完成。。。必须删除所有其他传入事件。。如果
flatMap流
完成,它可能会再次发生另一个事件…如上面的评论所述,使用
cofflate
无法实现OP想要的操作。cofflate不起作用。。不会删除最新的值。。它掉了最老的。。。以下是文档:“/***在
通道(…)
工厂函数中请求一个合并的通道。这是创建带有[
onBufferOverflow=DROP\u OLDEST
][BufferOverflow.DROP\u OLDEST].*/”的通道的快捷方式,但尚未尝试,但如果这样做有效,这不应该是
buffer的实现吗(RENDEZVOUS,DROP\u LATEST)
无论如何?因为RENDEZVOUS==0。我自己最初也这么认为,但是文档中说“要实现任何一种自定义策略[DROP\u LATEST/DROP\u LATEST],至少要使用一个元素的缓冲区。”聪明的解决方案,但这也不起作用。我得到了以下输出:
A的事件,B的事件,C的事件,C1,C2,C3
。我想这是因为这个函数在继续使用
flatMapConcat
之前会从上游流发出所有事件。您是否替换了
缓冲区(0,BufferOverflow.DROP\u最新)
在使用
dropIfBusy()
的代码中?我使用它获得预期的输出,如果这仍然不起作用,它可能取决于上下文。
scope
使用什么调度程序?