https://kotlinlang.org logo
Title
s

Samoxive

09/03/2018, 11:28 AM
i am a confused with coroutines, i haven't been able to find information on how they actually run in jvm, so let me ask this
fun blockingFunction(): Int {
    val foo = blockingFoo();
    val bar = blockingBar(bar);
    val baz = blockingBaz(bar);
}
normally, you would run this in an executor, get the integer via a future object or something
m

Martin Devillers

09/03/2018, 11:33 AM
Have you read this? https://github.com/Kotlin/kotlinx.coroutines/blob/master/coroutines-guide.md It’s really the only guide you need for coroutines
s

Samoxive

09/03/2018, 11:38 AM
i did, however it's not clear if i have to mark every blocking call as suspending for coroutines to not block unnecessarily
the guide assumes i have control over every function
m

Martin Devillers

09/03/2018, 11:58 AM
Basically, the answer is that if you want to leverage the power of coroutines, then yes you’ll have to turn your blocking functions into suspending functions. Otherwise, nothing’s preventing you from doing
async { blockingFunction() }.await()
, it’ll work and it’ll do the computing asynchronously, but it’ll starve the coroutine context of a thread while it’s blocked. The intermediate solution is something like
newSingleThreadContext().use { async(it) { blockingFunction() }}
, which will work pretty much the same as your code currently does, but it can act as a seam for new code calling this one with coroutines.
The complete answer would depend on why your functions are currently blocked, because that would determine how to turn this blocking behavior into a suspending behavior
s

Samoxive

09/03/2018, 12:01 PM
right, most of them are networking calls, which my program does a lot of
i was also expecting to use
async { block() }.await()
method, but since you are saying that it would starve the global coroutine thread pool, i fail to see how coroutines help here
because in java version, i was using cached thread pool, i could use the same thread pool with my now coroutine jobs but they would be blocking a thread either way
m

Martin Devillers

09/03/2018, 12:04 PM
My current solution for network calls is retrofit + coroutine adapter https://github.com/JakeWharton/retrofit2-kotlin-coroutines-adapter It’s an interesting solution because it essentially adapts the callback-based mechanism of retrofit into coroutines. This way the HTTP client continues to manage its own thread pool, but we adapt the calls with coroutines as soon as we need their result.
However if you want to actually migrate you network stack’s threading to coroutines, then you can simply use
ExecutorService.asCoroutineDispatcher
to obtain a context from your current cached thread pool, and do an
async
with that context
s

Samoxive

09/03/2018, 12:08 PM
thanks, i see. so the only benefit i would get from coroutines is less overhead with context switches?
m

Martin Devillers

09/03/2018, 12:18 PM
The benefit you would get from coroutines is the whole style of programming. I don’t know how you’re using the result of these requests right now, but I imagine it’s something like
executor.execute { 
    val result = blockingFunction()
    doOnUiThread {
        // Something with result
   }
}
With coroutines you’ll be able to combine it with other work in an imperative manner
launch(UI) {
    val result = async(NetworkContext) { blockingFunction }
    // Something with result
}
s

Samoxive

09/03/2018, 12:22 PM
right, i don't need that, so i suppose i will stick to the current implementation
much appreciated