Hi everyone :wave: Can anybody explain me what hap...
# coroutines
g
Hi everyone 👋 Can anybody explain me what happens with second
Deferred
in
select
when the first one returns value?
Copy code
select {
   deferred1.onAwait { it }
   deferred2.onAwait { it }
}
e
Nothing happens to it.
g
So, should I cancel it manually, if I want to get result from one coroutine exclusively?
e
Yes, you should cancel it yourself if you don’t need its result. You can just cancel them all (no harm in cancelling a completed one)
g
Thank you, I thought that I was wrong doing like this.
What do You think about this construction? It allows us to cancel all async operations without iterating through them. Developer still can forget to call
async
with
job
, but think that this is more reliable than cancel every
Deferred
.
Copy code
val job = Job()
val select = select {
    async(job) { suspend1() }.onAwait { it }
    async(job) { suspend2() }.onAwait { it }
}
job.cancelChildren()
e
@genovich This construction opts out of the structured concurrency. As usual with all such approaches it has a bug. If one suspend function crashes, then exception is throws and the other leaks, continues to work forever. If a parent coroutine is cancelled, then
select
throws
CancellationException
, but both async jobs continue to work
You can do a similar trick, though, but with the structured concurrency:
Copy code
val result = coroutineScope {
    select {
        async { suspend1() }.onAwait { it }
        async { suspend2() }.onAwait { it }
    }.also { 
        coroutineContext.cancelChildren()  
    }
}
👍 2
g
Oh, yes, I forget that I should connect the
job
to current context, and totally forget about exceptions. Your solution looks great, thank you.