如何使用Kotlin通道实现自然(又称智能)批处理?

如何使用Kotlin通道实现自然(又称智能)批处理?,kotlin,kotlinx.coroutines,Kotlin,Kotlinx.coroutines,自然的。智能批处理是流处理中的一种技术,它在不影响延迟的情况下优化吞吐量。在并发队列的示例中,使用者能够在某个时刻原子地耗尽所有观察到的项,然后将它们作为批处理。理想情况下,队列应该是有界的,为批量大小提供一个上限,同时向发送方提供反压力 它被称为“自然”批处理,因为没有强制的批处理大小:当流量较低时,它将在每个项目到达后立即处理。在这种情况下,您不需要通过批处理项目来优化吞吐量。当流量增加时,使用者将自动开始处理更大的批处理,从而摊销单个操作(如数据库INSERT)的固定延迟 我编写了一些实现

自然的。智能批处理是流处理中的一种技术,它在不影响延迟的情况下优化吞吐量。在并发队列的示例中,使用者能够在某个时刻原子地耗尽所有观察到的项,然后将它们作为批处理。理想情况下,队列应该是有界的,为批量大小提供一个上限,同时向发送方提供反压力

它被称为“自然”批处理,因为没有强制的批处理大小:当流量较低时,它将在每个项目到达后立即处理。在这种情况下,您不需要通过批处理项目来优化吞吐量。当流量增加时,使用者将自动开始处理更大的批处理,从而摊销单个操作(如数据库
INSERT
)的固定延迟

我编写了一些实现基本目标的代码:

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*

const val batchLimit = 20

@ObsoleteCoroutinesApi
suspend inline fun <T: Any> ReceiveChannel<T>.consumeBatched(
        handleItems: (List<T>) -> Unit
) {
    val buf = mutableListOf<T>()
    while (true) {
        receiveOrNull()?.also { buf.add(it) } ?: break
        for (x in 2..batchLimit) {
            poll()?.also { buf.add(it) } ?: break
        }
        handleItems(buf)
        buf.clear()
    }
}
导入kotlinx.coroutines*
导入kotlinx.coroutines.channels*
const val batchLimit=20
@废弃的公司程序
挂起inline fun ReceiveChannel.consumeBatched(
handleItems:(列表)->单位
) {
val buf=mutableListOf()
while(true){
receiveOrNull()?。也可{buf.add(it)}?:中断
对于(x/2..batchLimit){
poll()?。也可以{buf.add(it)}?:break
}
handleItems(buf)
buf.clear()
}
}
我们可以用以下方法进行测试:

@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
fun main() {
    val chan = generateMockTraffic()
    runBlocking {
        chan.consumeBatched { println("Received items: $it") }
    }
}

@ExperimentalCoroutinesApi
private fun generateMockTraffic(): ReceiveChannel<Int> {
    return GlobalScope.produce(capacity = batchLimit) {
        (1..100).forEach {
            send(it)
            if (it % 10 == 0) {
                delay(1)
            }
        }
    }
}
@ObsoleteCoroutinesApi
@实验常规
主要内容(){
val chan=generateMockTraffic()
运行阻塞{
chan.consumerBatched{println(“已接收项目:$it”)}
}
}
@实验常规
private fun generateMockTraffic():ReceiveChannel{
返回GlobalScope.Product(容量=批次限制){
(1..100)forEach{
发送(it)
如果(它%10==0){
延迟(1)
}
}
}
}
consumeBatched()
一次轮询队列中的一个项目,因此必须另外施加批次限制。如果针对Agrona项目这样的并发队列编写,它将更为理想,Agrona项目支持
drain
操作

有没有更好的方法与Kotlin频道,从图书馆得到更多的支持

如果不是,这是否会被视为一项需要添加的功能

有没有更好的方法与Kotlin频道,从图书馆得到更多的支持

库不支持此功能

如果不是,这是否会被视为一项需要添加的功能

它取决于所需的API曲面
drain
成员不太可能适合通道语义:它约束实现,它应该以某种方式公开drain限制,并为通道提供更多“类似于集合”的API。例如,
drain
在不受限制的频道中应该如何表现?是否有可能以有效的方式实施
排放
(使用预先设置大小的缓冲区,但避免oom和无限收集)一次,并将其用于任何渠道实施

可以改进的是来自通道的额外提示,例如预期容量和排队元素的计数。它们可以有一个宽松的语义和默认的实现,并像一些合理的可配置上界的
drain
扩展的提示。这样的API可以在将来添加,请随意使用