https://kotlinlang.org logo
Title
d

Dibya Ranjan

06/23/2020, 1:35 PM
Hey Kotliners, I am puzzled by one behaviour in
async
function. Here is the use case:
val deferred1 = GlobalScope.async {
   // rest-call-one
}

val deferred2 = GlobalScope.async {
   // rest-call-one
}

val deferred3 = GlobalScope.async {
   // rest-call-one
}

runBlocking {
    deferred1.await()
    deferred2.await()
    deferred3.await()
}
I have added some metrics to capture how well these are executed. Each of the calls take 20ms however, collectively they take 200ms. The CPU metrics shows that these threads are not getting starved. The usage is pretty low. I am wondering is this the right way to use
async
any guidance would be really helpful. Thank you.
r

r4zzz4k

06/23/2020, 1:39 PM
Ideally you would do the following:
coroutineScope {
    launch {
        // rest-call-one
    }

    launch {
        // rest-call-two
    }

    launch {
        // rest-call-three
    }
}
Outer scope would wait for everything to finish. Replace launches with async-await if you need results (you didn't use it so launch is more logical).
d

Dibya Ranjan

06/23/2020, 1:44 PM
Hello Andrew, Thanks for your help. Yes, I can replace
async
I am not using that. the new code looks like
runBlocking {
    corouteScope {
        // All launch here 
    }
}
Is this the right way to use it?
r

r4zzz4k

06/23/2020, 1:48 PM
runBlocking
creates it's scope, so you don't need an additional one. Though
runBlocking
, well, blocks, so make sure that's the thing you really need. To my experience,
runBlocking
is often used as a single bridge between blocking and suspending worlds -- e.g. in your
main
, in route handler for backend frameworks not supporting coroutines natively, in test methods. You don't need it when you, for example, already entered suspending world.
l

louiscad

06/23/2020, 2:26 PM
Also,
runBlocking
has a single thread in its dispatcher, so if it's blocked by some work… you know that the other work will be blocked for that time.
r

r4zzz4k

06/23/2020, 2:28 PM
Oh wow, that's news to me. Thanks, additional point for future replies like this :)
l

louiscad

06/23/2020, 2:29 PM
It's all in the doc. You can pass
Dispatchers.Default
or whatever to
runBlocking
if needed of course.
d

Dibya Ranjan

06/23/2020, 2:35 PM
Well, I am more confused now. In java, I would use a fork join pool and wait till all 3 tasks are done. How do I do that in Kotlin? Even though I have a suspended method, I need to call it inside a context which grantees that the thread waits till all 3 tasks are done.
l

louiscad

06/23/2020, 2:50 PM
@Dibya Ranjan There's this great talk about structured concurrency that might help you understand things:

https://www.youtube.com/watch?v=Mj5P47F6nJg

The rest, reading the docs should be helpful.
🙏 1