-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
combine(Iterable<Flow>) is very slow #2296
Comments
Thanks for the report!
Could you please elaborate on what exactly would you like to see in the documentation?
It's okay if it suits you, but please beware that it doesn't comply our
will print
which probably is not expected. |
@qwwdfsad true. I'm aware that Flows are slower than Lists in general. And I think and hope that most developers are. These 40k objects of mine cause several coroutines each so I probably have several 100k of coroutines. Yet all operations finish in a matter of second to milliseconds. In this specific case I was looking for a Flow-version of My implementation does indeed yield different results. That is in part because the current documentation is not clear on how exactly
My implementation also combines the most recently emitted values of each flow. It just happens to ignore intermediary values where newer ones are available. That's okay for me because I'm only interested in the most recent combination and not in intermediary results. The fact that In addition to improving the documentation maybe it makes sense to add a version like mine as an alternative operator. One that is super fast as it explicitly only cares about the most recent state and skips intermediate values if there are newer ones available. It can probably be optimized even further that my simple implementation. When I was looking for a solution to turn my |
Hi, @qwwdfsad, import kotlinx.coroutines.flow.*
suspend fun main() {
val flow = flowOf("a", "b", "c")
val flow2 = flowOf("1", "2", "3")
println(flow.combine(flow2) { i, j -> i + j }.toList())
} on my AMD A8-3870 can be
|
@qwwdfsad was writing exactly the same as @fvasco - same applies for online playground: https://pl.kotl.in/3qubtJaOh |
Yes, with |
So |
The expected result should be Regarding the proposed operator, we cannot accept it for multiple reasons:
The only resolution for this issue is to improve the performance of |
Great, that explanation should be part of the documentation 👍 I guess it's not possible to optimize the multi-threaded case by not making it fair but fast instead? Regarding my problem I don't see how optimizing
Regarding a new operator:
So what I need would perfectly describe a There's deprecation in place for |
Hi @fluidsonic, |
I had to change my implementation to use @fvasco I ran a quick test with 5k Flows of 2 values each. All Flows are static, i.e. Using
Using
Just for fun -
|
* Get rid of two code paths * Get rid of accidental O(N^2) where N is the number of flows * Get rid of select that hits performance hard Fixes #2296
The problem was pretty simple -- accidental and well-hidden Thanks for pointing it out! |
Awesome and thanks @qwwdfsad. I'll check it out. |
The
combine(…)
function becomes very slow the depending on the amount of Flows.Flat-mapping a 40k
List<List<…>>
takes approx. 11ms. With one element per list.Flat-mapping a 40k
List<Flow<…>>
takes approx. 1 minute. With one element per Flow.And that's with a very very simple non-suspending test case.
If
combine
is expected to have such a low performance it should be documented, otherwise developers like me treat is as a simple Flow-version ofList<List<…>>.flatten()
.If it's not expected then there is a bug.
My use case
I have ~40k objects in memory. For each object there is a Flow and a coroutine that periodically refreshes the object from the server when it's expired and emits that. At some point I have to continuously merge the latest version of all 40k objects into a single list for further processing. For that I use
combine(listOfObjectFlows) { it.toList() }
.Unfortunately that takes somewhere north of 15 minutes already. I have no time to let it finish to see the total…
I've written my own implementation now as a workaround.
Test code
The text was updated successfully, but these errors were encountered: