jeggy
01/14/2020, 6:27 PMwithContext
function, it waits for that coroutine to finish before continuing. But I want to launch multiple coroutines into another context and then later on, I will call join on that coroutine when I know I'm finished. How would I achieve something like this? I wrote a bare minimum example of what I'm trying to achieve here: https://pl.kotl.in/Ns6Hwa_8uoctylFractal
01/14/2020, 6:30 PMlaunch(coroutineContext)
not good enough?Casey Brooks
01/14/2020, 6:37 PMwithContext
is usually used to change the Dispatcher, so the coroutines execute on a different thread. The lambda of that function is packed and tossed in a queue on the specified dispatcher, and the parent coroutine will continue executing in its original context.
Since you’re using runBlocking
as the parent context, the join()
will wait for the doLaunch
calls to complete. But since runBlocking
is single-threaded, it cannot exit the parent context and process the new jobs added to the queue from the withContext
call. It’s deadlocked.runBlocking
, not withContext
jeggy
01/14/2020, 6:43 PMCasey Brooks
01/14/2020, 6:48 PMDispatchers.Main
onto <http://Dispatchers.IO|Dispatchers.IO>
, you’ll be just fine, and you can safely join the child jobs to the parent in the Main
context. But launching from Main
onto Main
will cause problems, again, because it is single-threaded, and the queue cannot complete the parent task to start executing the child-tasksjeggy
01/14/2020, 7:06 PMoctylFractal
01/14/2020, 7:27 PMwithContext
before async
? that doesn't really affect anything, async
isn't a suspend function so withContext
doesn't affect itjeggy
01/14/2020, 7:40 PMasync(this.coroutineContext)
instead of withContext(this.coroutineContext){async(this.coroutineContext){block(..)}}
all data get's lostoctylFractal
01/14/2020, 7:48 PMloadAllAtOnce(it).await()
? you never complete any of the deferreds, so of course that suspends forever?Casey Brooks
01/14/2020, 7:51 PMDeferredJsonMap
is a map of objects, but you’re initializing it with deferred objects. That means at any given node in that tree, it’s going to synchronously wait for all objects in that node to be ready before continuing to populate the rest. But you’re awaiting a result in the middle that won’t be completed until later. Or, if you run the jobs async, the tree will be fully constructed before they get executed, and so cannot be added to the tree when they finish.
What you need to do is first construct a tree of purely deferred objects. Once all the entire deferred tree has been constructed, then go through the entire thing and join to wait for the results of all of them to be finished.
I’ve updated your example to populate the tree with deferreds first, and then complete. I think this is doing what you’re wanting. I’ve also added some logging traces which help illustrate how it’s executing https://pl.kotl.in/-BRc6p9wDoctylFractal
01/14/2020, 7:52 PMwithContext
provides a CoroutineScope
as this
as well, so withContext { async {} }
will suspend until the async block completes, rather than launching on the DeferredJsonMap
scopewithContext
changes things upCasey Brooks
01/14/2020, 8:06 PMjeggy
01/14/2020, 10:19 PM"someArray" toDeferredValue listOf(25, 50, 100).asDeferredArray { num ->
delay(100)
"id" toValue JsonPrimitive(num)
}
Casey Brooks
01/15/2020, 1:40 AMDeferredJsonArray
class which holds its data in lists instead of maps, and set it up similar to the Map one. And then add a toDeferredArray
method to the map class which will create the builder for it. Here’s an updated example (it could probably be cleaned up/abstracted a bit, but it looks like it works just fine) https://pl.kotl.in/FUE07Z7Lujeggy
01/15/2020, 9:19 AM