轻松搞定Kotlin的Flow, ChannelFlow和CallbackFlow - 1

891 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 20 天,点击查看活动详情

轻松搞定Kotlin的Flow, ChannelFlow和CallbackFlow

理解Flow及其变体的妥善应用

在去年年初的某些时候, 我探索并理解Flow, 并将其与Sequence进行比较. Flow允许异步地处理数据流.

现在, 除了Flow, 我们还有ChannelFlowCallbackFlow. 它们与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

从这里, 我们可以看到, 每个发射都必须在下一个发射之前被消耗掉. 原因是, 没有缓冲区来存储额外的发射, 因此每个发射过程都必须排队.

1_L9xhIbPjMRxNgYbiTr5tww.webp

原因是, 发射和消费都是在没有任何通道的情况下同步进行的.

如果我们想确保在前一个音符被消耗之前没有发射, 这是好事. 然而, 它确实减慢了发射的过程.

添加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_mEoeFhF0DX4h6slZBYZo-g.webp

缓冲区能使处理加快一些.

让我们看看如果我们缓冲区大小为1, 即.buffer(1), 会怎么样. 其结果如下:

Emitting 1
Emitting 2
Emitting 3
Consuming 1
Emitting 4
Consuming 2
Emitting 5
Consuming 3
Consuming 4
Consuming 5

这将允许在任何消费之前的第一个目标中完成3个发射. 因此, 它加快了整个发射过程.

1_vDAE_X664-Y7XDTyH8bUMg.webp

如果添加.buffer(2)的话, 结果如下:

Emitting 1
Emitting 2
Emitting 3
Emitting 4
Consuming 1
Emitting 5
Consuming 2
Consuming 3
Consuming 4
Consuming 5

1_Ghriyg748xO-ge8Ely64mw.webp

有了.buffer(3)的情况下, 我们可以立即完成这5个数据的所有发射. 结果如下:

Emitting 1
Emitting 2
Emitting 3
Emitting 4
Emitting 5
Consuming 1
Consuming 2
Consuming 3
Consuming 4
Consuming 5

1_t8Nx1gkrAla9AAwZRbU59g.webp

我们可以看到Buffer是如何加快发射过程的.

敬请期待ChannelFlow...

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 20 天,点击查看活动详情