开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 20 天,点击查看活动详情
轻松搞定Kotlin的Flow, ChannelFlow和CallbackFlow
理解Flow及其变体的妥善应用
在去年年初的某些时候, 我探索并理解Flow, 并将其与Sequence进行比较. Flow允许异步地处理数据流.
现在, 除了Flow, 我们还有ChannelFlow和CallbackFlow. 它们与Flow有什么不同吗?
要了解这些, 让我们首先开始研究基本的Flow.
Flow
让我们来看看这个简单的代码: 发出1到5的值的.
fun main() = runBlocking {
flow {
for (i in 1..5) {
println("Emitting $i")
emit(i)
}
}
.collect { value ->
delay(100)
println("Consuming $value")
}
}
结果如下:
Emitting 1
Consuming 1
Emitting 2
Consuming 2
Emitting 3
Consuming 3
Emitting 4
Consuming 4
Emitting 5
Consuming 5
从这里, 我们可以看到, 每个发射都必须在下一个发射之前被消耗掉. 原因是, 没有缓冲区来存储额外的发射, 因此每个发射过程都必须排队.
原因是, 发射和消费都是在没有任何通道的情况下同步进行的.
如果我们想确保在前一个音符被消耗之前没有发射, 这是好事. 然而, 它确实减慢了发射的过程.
添加Buffer
为了使发射速度更快, 我们可以给它增加一个缓冲区. 让我们试试用0缓冲区.
fun main() = runBlocking {
flow {
for (i in 1..5) {
println("Emitting $i")
emit(i)
}
} .buffer(0)
.collect { value ->
delay(100)
println("Consuming $value")
}
}
结果如下:
Emitting 1
Emitting 2
Consuming 1
Emitting 3
Consuming 2
Emitting 4
Consuming 3
Emitting 5
Consuming 4
Consuming 5
尽管是0缓冲区, 但增加缓冲区确实可以给缓冲区增加一个发射量.
缓冲区能使处理加快一些.
让我们看看如果我们缓冲区大小为1, 即.buffer(1), 会怎么样. 其结果如下:
Emitting 1
Emitting 2
Emitting 3
Consuming 1
Emitting 4
Consuming 2
Emitting 5
Consuming 3
Consuming 4
Consuming 5
这将允许在任何消费之前的第一个目标中完成3个发射. 因此, 它加快了整个发射过程.
如果添加.buffer(2)的话, 结果如下:
Emitting 1
Emitting 2
Emitting 3
Emitting 4
Consuming 1
Emitting 5
Consuming 2
Consuming 3
Consuming 4
Consuming 5
有了.buffer(3)的情况下, 我们可以立即完成这5个数据的所有发射. 结果如下:
Emitting 1
Emitting 2
Emitting 3
Emitting 4
Emitting 5
Consuming 1
Consuming 2
Consuming 3
Consuming 4
Consuming 5
我们可以看到Buffer是如何加快发射过程的.
敬请期待ChannelFlow...
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 20 天,点击查看活动详情