Kotlin 协程: Channel vs Flow

80

我最近一直在学习和阅读关于 Flow 和 Kotlin 协程的内容。但是我仍然困惑于何时应该使用 Flow,何时应该使用 Channel

起初看起来更简单。处理热数据流?使用 Channel。冷数据流?使用 Flow。如果您需要从多个位置监听数据流,则同样适用;在这种情况下,应选择 Channel。仍有许多示例和问题。

但是最近引入了 FlowChannels,以及大量鼓励使用 Flow 的方法和类,其方便将 Channel 转换为 Flow 等。随着每个 Kotlin 发布中出现的所有新内容,我越来越困惑。因此问题是:

我应该在什么时候使用 Channel,什么时候使用 Flow


4
https://youtu.be/tYcqn48SMT8 - IR42
3个回答

68

对于许多以前最好的工具是Channel的用例,现在Flow已经成为了新的最佳工具。

作为一个具体的例子,callbackFlow现在是接收来自第三方API回调数据的最佳方法。在GUI设置中,这种方法特别有效。它将回调、通道和相关的接收协程都封装在同一个独立的Flow实例中。当收集流时,只有注册回调。流的取消会自动传播到关闭通道和注销回调。您只需要提供一次回调注销代码。

您应该将Channel看作是Flow在其实现中使用的较低级别的原语。仅在意识到Flow无法满足您的要求后,考虑直接使用它。


4
函数的文档中提供了丰富且有注释的示例。 - Marko Topolnik
使用MutableStateFlow时需要一个初始值,而在Channels中则不需要。 - Iglesias Leonardo

28

我认为这里提供了一个很好的解释 (Roman Elizarov) 冷流,热通道:

通道非常适合模拟本质上是热的数据源,即不存在应用程序请求的数据源:传入的网络连接、事件流等。通道与futures一样,都是同步原语。当您需要在同一进程或不同进程的协程之间发送数据时,应使用通道。

但是如果我们既不需要并发,也不需要同步,只需要非阻塞的数据流怎么办? 直到最近,我们还没有这样的类型,因此欢迎 Kotlin 的 Flow 类型...

与通道不同,本质上不涉及任何并发。它们是非阻塞的,但是是顺序的。 流的目标是成为异步数据流的悬挂函数——方便、安全、易于学习和使用。


4
将Flows视为数据流,Channels视为队列。Flows主要用于处理连续不断的数据流,可能永远不会停止。它们非常适用于数据持续输入的场景,例如监控传感器读数或实时用户交互。
另一方面,Channels则像一个队列,您可以逐个放入和取出数据。然而,通过Channel发送的每个事件只能被单个订阅者消费,而不像Flows那样每个发射都被所有收集器共享。这种行为是Channels基本设计的一部分,通常称为“单消费者”语义。它确保数据的顺序和流动被保持,并且每个数据片段由单个协程或消费者处理。这个特性在需要保证按特定顺序处理数据或避免多个消费者同时访问同一数据时特别有用。当您只有一个消费者(协程)需要以受控方式接收数据,确保每个数据片段仅被消费一次时,Channels尤其有用。
当多个消费者正在从一个通道中主动消费数据时,通道的行为是按顺序轮流向每个消费者传递数据。这确保没有任何一个消费者独占所有数据,并且所有消费者都有机会处理他们接收到的数据。这种公平分配机制在同时有多个消费者工作的场景中特别有用,可以防止任何一个消费者垄断数据处理。它促进了资源的平衡利用,并防止应用程序出现潜在的瓶颈。
流具有内置的背压处理功能,可以帮助您在数据到达过快时进行管理。通道没有这个内置功能,因此在使用通道时需要手动处理背压。
参考链接:https://androidlearnersite.wordpress.com/2023/08/09/kotlin-flows-part-4/

流程具有内置的背压处理功能,可以帮助您在数据到达过快时进行管理。通道没有这个内置功能,因此在使用通道时,您需要手动处理背压。- 我不认为这是正确的,当没有消费者接收时,生产者会被挂起,这是一种简单有效的处理背压的方式:https://kotlinlang.org/docs/channels.html#buffered-channels - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接