Question for group: when you need to process a lis...
# coroutines
s
Question for group: when you need to process a list of items concurrently, do you: 🅰️ Create a new coroutine for every item in the list, or 🅱️ Create a small number of worker coroutines that process several items each, e.g. by reading from a channel? What do you think are the pros and cons of each approach? Have you come across any articles comparing the two styles?
🅰️ 5
d
Thanks for bringing this! I was not even aware that I should consider anything else than A 🙂 I was thinking of coroutines as an "infinitesimally" cheap resource that abstracts away from the expensive thread pool underneath.
e
it's not literally infinitely cheap, but if you can hold a list of inputs in memory, you can probably hold the list of pending work in memory too
f
A new coroutine is not much more expensive than a dispatched task waiting to be picked up by a worker coroutine AFAIK. "not having to reuse them" is part of the paradigm shift of coroutines vs threads
e
and even with a potentially unbounded
Flow
of inputs, you can process them with limited concurrency without having to managing worker coroutines, e.g.
Copy code
itemsFlow.flatMapMerge(concurrency = N) { item ->
    flow {
        emit(process(item))
    }
}
d
For me it depends on the amount of items in the list and whether the processing of each item needs to be concurrent (as in each item causes an expensive network call). If that's true, I just usually spawn a coroutine for each item in the list in a wrapped coroutine scope, but this causes an error in one item to cause the entire processing to be cancelled which may or may not be what you want
r
I recently took the same approach that Ephemient mentioned above (just created an extension function encapsulating the flatMapMerge). While coroutines are rather lightweight and can easily be handled concurrently, it's also very important to consider that if you are touching other downstream resources or services, limiting them to a sensible level of concurrency can be a great idea in case they can't hold the backpressure properly
related question: Does anyone know the status of the
.parallel()
operator that the Kotlin team wanted to implement? AFAIK they wanted this parallelism / flow control to not exist in bespoke operators, but rather in a "mode" of sorts
s
Thanks for all the replies! Controlling the amount of concurrency was the only real advantage I could think of to approach 🅱️. I like the creative use of flows to solve the same problem 👍 I wouldn't have thought of that.