How to ensure sequential execution of asynchronous calls in Kotlin? - kotlin

class BlockEventManager(private val scope: CoroutineScope) {...}
private val blockEventManager = BlockEventManager(viewModelScope) ...
fun doSomethingUsefulOneAsync() {
'some remote service call
}
fun doSomethingUsefulTwoAsync() {
'some other remote service call dependent on doSomethingUsefulOneAsync()
}
How do we achieve if doSomethingUsefulOneAsync has completed then execute doSomethingUsefulTwoAsync. I don't believe async.await() is set up for this right?
blockEventManager.startBlockingAsyncWork {
val step1 = async { doSomethingUsefulOneAsync() }
step1.await()
doSomethingUsefultwoAsync() //will this execute only after step1 completes or fails?
...

I don't know what your blockEventManager is, but I'm assuming startBlockingAsyncWork takes a suspend function as a parameter and invokes it in a coroutine.
One of the key features of coroutines is structured concurrency, and it is absolutely guaranteed that your calls are sequential, so calling await on the first Deferred guarantees that doSomethingUsefulOneAsync() will return before the execution flow continues.
However, if you want to do these actions sequentially, you shouldn't introduce async in the first place. Just call the two functions, one after the other.
It's a code smell that a suspend function would ever have the term "async" in its name. A properly composed suspend function does its work in a suspending way and then returns its result (if it has one). For example, a suspend function should not start a network call and return without waiting for the result before returning. But by waiting, I mean by suspending the coroutine until the result is received, not blocking the thread.

Related

Calling a non-inlined library function with a suspending lambda that could have been inlined

I am calling a non-inlined library function, providing my own function f that needs to suspend because it receives from a channel. When the library function is called I simply want to wait for it to complete in the current context. The library function will always call f within its body (specifically, the library function does pre, f, then post, where f must be called between pre and post, so it could have been an inlined function). However within f the outer coroutine context no longer applies.
My first thought was to surround the suspending call with runBlocking, but this causes a deadlock, because the (potentially single) thread is now blocked until receive completes, which prevents the producer from progressing.
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
// Some non-inlined library function that calls given function f immediately with some library provided value
fun libraryFunction(f: (Int) -> Int) =
f(5)
fun main() {
// Some outer loop that may sometimes only have 1 thread
runBlocking(newSingleThreadContext("thread")) {
// An existing channel
val channel = produce {
send("whatwewant")
}
// Our code
libraryFunction { libraryProvidedValue ->
println(libraryProvidedValue)
runBlocking {
println(channel.receive())
}
// A return value the library needs
7
}
}
}
What is the best way to solve this issue? Can using the inner runBlocking be prevented?
In other words: is there anyway to pinky-promise that we are, in fact, still within the same coroutine in the lambda function?
As an additional illustration, the following works:
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
// Some non-inlined library function that calls given function f immediately with some library provided value
fun libraryFunction(f: (Int) -> Int) =
f(5)
fun main() {
// Some outer loop that may sometimes only have 1 thread
runBlocking(newSingleThreadContext("thread")) {
// An existing channel
val channel = produce {
send("whatwewant")
}
// <inline the start of the body of libraryFunction here> (which gives libraryProvidedValue)
// Our code
println(libraryProvidedValue)
println(channel.receive())
// <inline the end of the body of libraryFunction here>
}
}
Update: In this case, the only real issue seems to be that the compiler is not aware of the surrounding coroutine being the same in the lambda function body - but the code is entirely possible to run successfully if it did (as can be seen by inlining the library function). In essence, there is nothing wrong with the flow of this code in particular (because the library function calls the lambda function within its body), but it is a shortcoming in the lack of guarantees the compiler can determine. While runBlocking makes the compiler happy, it has unwanted side effects (notably, the nested blocking part, which makes communication with the outside difficult due to the outer runBlocking blocking up the potentially only thread).
Because of this, I decided to rewrite my entire code surrounding this in a style that uses Deferred with an await at the top level, instead of suspend functions. I would regard this as very un-kotlin-ic, and it comes with potential problems of its own (like resource leaks), but it works for my scenario.
Note that this still does not answer the question posed in any way, but I wanted to note it as an alternative decision to make for future users faced with a similar problem.
Unfortunately there is only one way to achieve what you want - to use runBlocking, but it has consequences like you described. suspend functions should be called from a coroutine (runBlocking in this case) or another suspend function. So to achieve this without using runBlocking libraryFunction function must accept a suspend f function and be suspend itself:
suspend fun libraryFunction(f: suspend (Int) -> Int) = f(5)
I would suggest first to receive the value from the channel, and then call the libraryFunction:
runBlocking(newSingleThreadContext("thread")) {
// An existing channel
val channel = produce {
send("whatwewant")
}
// Our code
val receivedValue = channel.receive()
libraryFunction { libraryProvidedValue ->
println(libraryProvidedValue)
println(receivedValue)
// A return value the library needs
7
}
}

Should be used a CoroutineScope's extension function or a suspending function

I'm writing an app using coroutines (code below is greatly simplified). Recently I've watched Coroutines in Practice talk and got a little confused. Turns out I don't know when to use a CoroutineScope's extension function and when to use a suspending function.
I have a mediator (Presenter/ViewModel/Controller/etc) that implements CoroutineScope:
class UiMediator : CoroutineScope {
private val lifecycleJob: Job = Job()
override val coroutineContext = lifecycleJob + CoroutineDispatchersProvider.MAIN
// cancel parent Job somewhere
fun getChannel() {
launch {
val channel = useCase.execute()
view.show(channel)
}
}
}
Business logic (Interactor/UseCase):
class UseCase {
suspend fun execute(): RssChannel = repository.getRssChannel()
}
And a repository:
class Repository {
suspend fun getRssChannel(): RssChannel {
// `getAllChannels` is a suspending fun that uses `withContext(IO)`
val channels = localStore.getAllChannels()
if (channels.isNotEmpty()) {
return channels[0]
}
// `fetchChannel` is a suspending fun that uses `suspendCancellableCoroutine`
// `saveChannel` is a suspending fun that uses `withContext(IO)`
return remoteStore.fetchChannel()
.also { localStore.saveChannel(it) }
}
}
So I have a few questions:
Should I declare Repository#getRssChannel as a CoroutineScope's extension function (because
it spawns new suspending functions: getAllChannels,
fetchChannel, saveChannel)? How can I use it in the UseCase then?
Should I just wrap a Repository#getRssChannel into a
coroutineScope function in order to make all spawned suspending
functions to be children of the latter?
Or maybe it's already fine and I should change nothing. When to
declare a function as a CoroutineScope's extension then?
A suspending function should return once it has completed its task, it executes something, possibly taking some time while not blocking the UI, and when it's done it returns.
A CoroutineScope extension function is for a fire-and-forget scenario, you call it, it spawns a coroutine and returns immediately, while the task continues to execute.
Answer to question 1:
No, you should not declare Repository#getRssChannel as an extension function of CoroutineScope, because you only invoke suspend functions but not start (launch/ async) new jobs. As #Francesc explained extension function of CoroutineScope should only start new jobs, but cannot return immediatly result and should not be declared as suspend by itself.
Answer to question 2:
No, you should not wrap Repository#getRssChannel into a CoroutineScope. Wrapping makes only sense if you start (launch/ async) new coroutines in this method. The new jobs would be children of the current job and the outer method will only return after all parallel jobs are finished. In your case you have sequential invocations of other suspending coroutines and there is no need of a new scope.
Answer to question 3:
Yes, you can stay with your code. If you would need the functionality of UiMediator#getChannel more then once, then this method would be a candidate of an extension function for CoroutineScope.

How can I return an awaited value in Kotlin?

I need test() to return a player from my db. I know I can use a callback but how can I make this work with async await?
fun test(): Player {
launch(UI) {
val player = async(CommonPool) { MainActivity.database?.playerDao()!!.loadPlayer() }.await()
return player
}
}
Currently the error is return is not allowed here
In JavaScript for example I would make test async then await it's result from where it's called.
It is impossible to run a coroutine on a raw thread. At the very least you must turn an existing thread into one that spins a top-level event loop. You achieve this with a runBlocking call on the very top of the thread's call stack (i.e., inside its run() method).
On a GUI thread or any other kind of thread that runs an event loop, you need a matching Dispatcher that submits coroutines to this event loop. Kotlin already provides dispatchers for Swing, JavaFX, Android etc. In these cases you need to launch a coroutine from some existing GUI event handler, like this:
myScope.launch {
val player = test()
... use the player ...
}
myScope must be an object that implements CoroutineScope with something like this:
override val coroutineContext = Dispatchers.Main + SupervisorJob()
This will give you a way to cleanly cancel all the coroutines running within the same scope, by calling
coroutineContext[Job]!!.cancel()
My example uses the Main dispatcher, which resolves to the GUI thread when you import the Kotlin coroutines library matching your UI framework.
The test() function must become a suspend fun that temporarily switches the dispatcher to a thread pool for blocking operations. Here's how a basic example could look:
suspend fun test() = withContext(Dispatchers.IO) {
MainActivity.database?.playerDao()!!.loadPlayer()
}
Finally, note I don't mention async at all in this answer. Kotlin's async has a very specific purpose, it is not a general facility like in other languages. Its purpose is strictly parallel decomposition, where you decompose a single task into several concurrent subtasks.

How to suspend a coroutine at a specific point

I am at loss with the following problem.
I have the following code:
val parentJob: Job = Job()
launch(parent = parentJob) {
while (true)
{
if (!parentJob.isCompleted)
{
// I want to control suspension here
println("Resumed")
}
}
}
I would like to be able to control, somehow akin to a semaphore, when should the coroutine suspend and when to resume exactly in the commented part of the snippet
I know there's suspendCancellableCoroutine but I am unsure how to use it or if it is appropriate here
How can this be achieved or are there any tutorials about this?
It would be more helpful to think about coroutines in terms of callbacks and continuations, not threads and semaphores.
Internally, when the coroutine is suspended, the entire chain of suspend fun calls returns with a special internal object, COROUTINE_SUSPENDED. So the whole execution of a coroutine is just a function call during which a callback object is being built up. This callback is the continuation and when you call it, execution resumes from the place which returned the special COROUTINE_SUSPENDED object.
Kotlin runs the block you pass to suspendCancellableCoroutine with the continuation object as the parameter. So you should save this object and make it available to the code outside the coroutine.
Here's some code that may help your understanding. Note there's no need to create a separate parent job if you want to cancel the coroutine. You can just cancel the Job instance that launch returns and the coroutine will not resume after suspension.
import kotlin.coroutines.*
import kotlinx.coroutines.*
var continuation: Continuation<String>? = null
fun main(args: Array<String>) {
val job = GlobalScope.launch(Dispatchers.Unconfined) {
while (true) {
println(suspendHere())
}
}
continuation!!.resume("Resumed first time")
continuation!!.resume("Resumed second time")
job.cancel()
continuation!!.resume("This shouldn't print")
}
suspend fun suspendHere() = suspendCancellableCoroutine<String> {
continuation = it
}
If you still need an explicit check (because there aren't enough suspension points on the execution path), you can just use the isActive property which is available directly to the block:
while (isActive) ...

does IO in coroutines cause suspension?

Inside a coroutine I am doing a http-request with OkHttpClient. The request is done from a function that has the suspend keyword:
suspend fun doSomethingFromHttp(someParam:String): Something {
...
val response = HttpReader.get(url)
return unmarshalSomething(response)!!
}
I assume that the function can be suspended on entry since it has the suspend keyword, but will the coroutine also be suspended when doing the http-request? What about other kinds of blocking IO?
There's no automagic going on with Kotlin coroutines. If you call a blocking function like HttpReader.get(), the coroutine won't be suspended and instead the call will block. You can easily assure yourself that a given function won't cause the coroutine to suspend: if it's not a suspend function, it cannot possibly do it, whether or not it's called from a suspend function.
If you want to turn an existing blocking API into non-blocking, suspendable calls, you must submit the blocking calls to a threadpool. The easiest way to achieve it is as follows:
val response = withContext(Dispatchers.IO) { HttpReader.get(url) }
withContext is a suspend fun that will suspend the coroutine, submit the provided block to another coroutine dispatcher (here IO) and resume when that block is done and has come up with its result.
You can also easily instantiate your own ExecutorService and use it as a coroutine dispatcher:
val myPool = Executors.newCachedThreadPool().asCoroutineDispatcher()
Now you can write
val response = withContext(myPool) { HttpReader.get(url) }
This PR has example code for proper OkHttp coroutines support
https://github.com/square/okhttp/pull/4129/files
It uses the thread pools of OkHttp to do the work. The key bit of code is this generic library code.
suspend fun OkHttpClient.execute(request: Request): Response {
val call = this.newCall(request)
return call.await()
}
suspend fun Call.await(): Response {
return suspendCancellableCoroutine { cont ->
cont.invokeOnCancellation {
cancel()
}
enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
if (!cont.isCancelled) {
cont.resumeWithException(e)
}
}
override fun onResponse(call: Call, response: Response) {
if (!cont.isCancelled) {
cont.resume(response)
}
}
})
}
}
There are two types of IO libraries in JAVA world, using IO or NIO.
You can find more documentation at https://dzone.com/articles/high-concurrency-http-clients-on-the-jvm
The ones using NIO, can theoretically provide true nonblocking suspension unlike IO ones which only offload the task to a separate thread.
NIO uses some dispatcher threads in the JVM to handle the input output sockets using multiplexing (Reactor design pattern). The way it works is, we request the NIO/dispatchers to load/unload something and they return us some future reference. This code can be turned into coroutines easily.
For IO based libraries, coroutine implementation is not true non blocking. It actually blocks one of the threads just like in Java, however the general usage pattern is, to use Dispatcher.IO which is a threadpool for such blocking IO tasks.
Instead of using OkHttpClient, I would recommend using https://ktor.io/docs/client.html