I came across a problem that I cannot figure out h...
# coroutines
a
I came across a problem that I cannot figure out how to achieve using coroutines. I have two
async
coroutines that both return the same type. I want to return only the value of the coroutine that finishes first and discard the value of the slower one. I have found that
select
takes care of selecting and returning value the faster coroutine but the other one is not cancelled and coroutineScope waits until the other one returns too. What would be the best approach?
Might this be the correct approach?
Copy code
suspend fun getFaster(): Int = coroutineScope {
    select<Int> {
        async { getFromServer() }.onAwait { it }
        async { getFromDB() }.onAwait { it }
    }.also {
        coroutineContext.cancelChildren()
    }
}
z
That's what I would do, it's nice and simple, but I kind of wish there was a version of
coroutineScope
that canceled its children after instead of joining on them, because this seems like a pretty common use case.
👍 1
j
Agree, simple approach 🙂 I’d like to throw an alternative out there and get both your thoughts on it (not entirely sure if its correct)
Copy code
fun getFromServer(): Flow<Int> { ... }
fun getFromDB(): Flow<Int> { ... }
suspend fun getFaster(): Int = flowOf(getFromServer(), getFromDB()).flattenMerge(2).first()
under the hood I suspect it’s not as efficient as the select approach, but I suppose that’s acceptable given network and db latencies
z
That's basically doing the same thing under the hood - launching two coroutines, then cancelling the slow one, just using channels instead of deferreds. I think flattenMerge probably even uses select.
It's more a question of which one more clearly expresses your intent/is more readable.