if i have a list of 10 deferreds, is there an easy...
# coroutines
c
if i have a list of 10 deferreds, is there an easy way each one of them as soon as it completes?
deferredList.mapResolved{deferredResult -> ... }
if i do it like this, is there a way to be sure that my launch blocks don’t interrupt each other? I want my println output not to be mixed up by threads
Copy code
suspend fun bla(deferred: List<Deferred<Context>>) {
    coroutineScope {
        deferred.forEach {
            launch {
                val context = it.await()
                println(
                    context.summary()
                )
            }
        }
        
    }
    
}
a
if you want the several printlns behave as if they were called from the one thread, you can create
Copy code
val singleThreadedContext = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
and then
Copy code
withContext(singleThreadedContext) {
    println(context.summary())
}
c
Great. Will that perform better than to make the Println synchronized on context?
a
I would recommend not using synchronized with coroutines because coroutines works on the concept of continuations and if you have suspending function call in the synchronized block, it can have undesirable behaviour
If you want the behaviour that synchronized provides, you can use
Copy code
val mutex = Mutex()
mutex.withLock { /* code */ }
If you want to know more about sharing mutable state, here is great article on https://kotlinlang.org/docs/reference/coroutines/shared-mutable-state-and-concurrency.html
c
hmm, but whats better? a task switch or a mutex? I guess the mutex will perform better. will the await change the dispatcher to the one where the deferred was resolved, or will it stay in the dispatcher of my async block?
z
if i do it like this, is there a way to be sure that my launch blocks don’t interrupt each other?
You mean you want the prints to be executed in the order of the list, regardless of which order the deferreds complete in?
c
I don’t even care about the order. i just want just one println to run at a time
each deferred is a result, the order does not matter
z
The code you wrote will definitely do that. And it will also do so in the same order, that of the list, every time. There’s no magic going on here.
c
well it will print each result as soon as the deferred is ready
z
The first iteration of the loop waits for the first deferred to complete. It doesn’t wait for or know about any of the other deferreds. Only when the first deferred completes, then the print, then the next deferred is awaited on, etc
c
if they all are already ready it will be the order of the list
z
Oh derp I missed the launch
Ok then the mutex solution makes sense. Although you could also convert your deferreds to Flows and use the merge operator
You could also create a channel, then from your launched coroutines send the results into the channel, and in your main coroutine, receive from the channel in a loop
c
it was a channel at some point then i converted it to a list of deferreds
but now i want to print the deferreds as soon as they are ready so maybe deferreds are not the best solution anymore
z
What’s your producer code look like?
right now contextExecutor returns a list of deferred (one for each test context). and those each contain a list of deferred for each test result. and I’m now printing the results for each context when all the test of that context are finished
so its a bit more complicated than my example
z
Hm, I don’t think anything there requires syncrhonization. You have a single print call per launched coroutine, and i believe print is effectively atomic on most systems.
that
asSequence()
call on
contextInfos
looks redundant though,
List
has
forEach
as well
c
i guess if println is not guaranteed to be atomic i can just wrap it with a mutex anyway