elye
10/12/2022, 9:58 AMchannelFlow
can do what flow
can't e.g.
• Retrieve value from a concurrently run coroutine
• Can use a non-suspending way i.e. `trySend` to send data
It looks like it is more powerful than flow
. I wonder
• if there's anything where flow
can do but not in channelFlow
, or
• if there's anything flow
is preferred over channelFlow
(e.g. in terms of efficiency or performance?)?
The reason I ask is, I want to see if we can just use channelFlow
for everything instead, or what's the scenario we should use flow
instead? I may have missed out something fundamental?Joffrey
10/12/2022, 10:41 AMchannelFlow
uses (you guessed it) a channel under the hood. The elements you send are sent via a channel and then go to the flow collector. This means there is some extra synchronization (and that's what allows you to send from other coroutines). I would assume this is more complex under the hood and might be slightly slower than a simple flow
(I haven't measured, though).
Why would you want to use channelFlow
for everything, though? If you just need a simple flow, why not use it?
Note that there is also callbackFlow
which is more appropriate when wrapping callback-based APIs that call their callbacks multiple times. It may warn you better if you're doing things wrong.elye
10/12/2022, 10:48 AMcallbackFlow
is actually channelFlow
that force (remind) us to use awaitClose
. That's all good.
I'm just curious on flow
vs the the channelFlow
, as I cannot really think of what one channelFlow
cannot do, other than suspect there's some complex performance behind the scene, as you mentioned.
It's more of a curious learning than actually having explore any use case.Joffrey
10/12/2022, 11:05 AMflow
can do more things than channelFlow
.
But I would argue that, even if there were no performance difference, being able to do less is often a good thing 🙂
For instance List
can do less than MutableList
, and this is the main reason why I use List
over MutableList
whenever I can. We usually don't conclude that, since MutableList
can do everything List
can, we should just use MutableList
everywhere.Nick Allen
10/13/2022, 6:53 AM(1..10).asFlow()
.onEach { println("onEach $it") } //Will print the 6
.buffer(1)
.take(5)
.collect { println("collect $it") }
Buffers also further complicate your code since every point where you use a buffer introduces concurrency. The upstream is running in a separate coroutine than the downstream meaning upstream operators can handle newer items concurrently while downstream operators handle older items. This can be exactly what you want in some cases but it can also be especially dangerous if side effects are involved.Joffrey
10/13/2022, 7:43 AMelye
10/13/2022, 9:40 AMelye
10/15/2022, 11:10 AMchannelFlow
with RENDEZVOUS
is not the same as Flow
. Explanation here. @Nick Allen is correct stating that the default Flow
behaviour where each emitting has to be wait for it to be consumed is unique to the Flow
itself.