Kotlin Coroutines: Channel vs Flow
Asked Answered
A

3

87

I'm recently studying and reading a lot about Flow and Kotlin Coroutines. But I still get confused about when I should use Flow and when I should use Channel.

At the beginning it looked more simple. Working with hot streams of data? Channel. Cold ones? Flows. Same goes if you need to listen to streams of data from more than a single place; if that's the case Channel is the choice to go. There are still a lot of examples and questions.

But recently FlowChannels where introduced, together with tons of methods and classes that encourage the use of Flow, which facilities transforming Channels into Flows and so on. With all this new stuff coming on each Kotlin release I am getting more and more confused. So the question is:

When should I use Channel and when should I use Flow?

Attainable answered 19/12, 2019 at 15:35 Comment(1)
youtu.be/tYcqn48SMT8Patella
S
77

For many use cases where the best tool so far was Channel, Flow has become the new best tool.

As a specific example, callbackFlow is now the best approach to receiving data from a 3rd-party API's callback. This works especially well in a GUI setting. It couples the callback, a channel, and the associated receiving coroutine all in the same self-contained Flow instance. The callback is registered only while the flow is being collected. Cancellation of the flow automatically propagates into closing the channel and deregistering the callback. You just have to provide the callback-deregistering code once.

You should look at Channel as a lower-level primitive that Flow uses in its implementation. Consider working with it directly only after you realize Flow doesn't fit your requirements.

Sin answered 20/12, 2019 at 14:22 Comment(2)
Extensive, well-commented example available in the function's documentation.Sin
With MutableStateFlow you need an initial value, which isn't needed in ChannelsArraign
C
32

In my opinion a great explanation is here (Roman Elizarov) Cold flows, hot channels:

Channels are a great fit to model data sources that are intrinsically hot, data sources that exist without application’s requests for them: incoming network connections, event streams, etc. Channels, just like futures, are synchronization primitives. You shall use a channel when you need to send data from one coroutine to another coroutine in the same or in a different process

But what if we don’t need either concurrency or synchronization, but need just non-blocking streams of data? We did not have a type for that until recently, so welcome Kotlin Flow type...

Unlike channels, flows do not inherently involve any concurrency. They are non-blocking, yet sequential. The goal of flows is to become for asynchronous data streams what suspending functions are for asynchronous operations — convenient, safe, easy to learn and easy to use.

Comehither answered 28/9, 2020 at 16:21 Comment(0)
B
6

Think of Flows as streams of data and Channels as queues. Flows are all about handling a continuous stream of data that might not stop. They’re great for scenarios where data keeps coming in, like monitoring sensor readings or real-time user interactions.

On the other hand, Channels work like a queue, where you can put data in and take it out one by one. However, each event sent through a Channel is consumed by a single subscriber, unlike Flows where each emissions are shared between all collectors.This behavior is part of the fundamental design of channels and is often referred to as “single-consumer” semantics. It ensures that the order and flow of data are maintained, and each piece of data is processed by a single coroutine or consumer.This characteristic is particularly useful in scenarios where you want to guarantee that data is processed in a specific order or where you want to avoid race conditions that might occur if multiple consumers access the same data simultaneously.Channels are particularly useful when you have a single consumer (coroutine) that needs to receive data in a controlled manner, ensuring that each piece of data is consumed only once.

When multiple consumers are actively consuming data from a channel, the channel’s behavior is such that it takes turns delivering data to each consumer in a sequential manner. This ensures that no consumer hogs all the data and that all consumers have the opportunity to process the data they receive.This fair distribution mechanism is particularly useful in scenarios where you have multiple consumers working concurrently, and you want to prevent any one consumer from monopolizing the data processing. It promotes balanced resource utilization and prevents potential bottlenecks in your application. Flows come with built-in backpressure handling, which helps you manage data when it’s coming in too fast. Channels don’t have this built-in feature, so you’ll need to handle backpressure manually when using Channels.

Reference : https://androidlearnersite.wordpress.com/2023/08/09/kotlin-flows-part-4/

Brina answered 9/8, 2023 at 14:44 Comment(1)
“Flows come with built-in backpressure handling, which helps you manage data when it’s coming in too fast. Channels don’t have this built-in feature, so you’ll need to handle backpressure manually when using Channels.“ - I don't think this is true, producers are suspended when there is no consumer to receive which is a nice simple way to handle backpressure: kotlinlang.org/docs/channels.html#buffered-channelsFatso

© 2022 - 2024 — McMap. All rights reserved.