https://kotlinlang.org logo
#coroutines
Title
# coroutines
g

genovich

04/10/2021, 5:25 PM
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

elizarov

04/10/2021, 5:34 PM
Nothing happens to it.
g

genovich

04/10/2021, 6:31 PM
So, should I cancel it manually, if I want to get result from one coroutine exclusively?
e

elizarov

04/10/2021, 7:10 PM
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

genovich

04/10/2021, 8:20 PM
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

elizarov

04/12/2021, 8:58 AM
@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

genovich

04/12/2021, 9:04 AM
Oh, yes, I forget that I should connect the
job
to current context, and totally forget about exceptions. Your solution looks great, thank you.
4 Views