问题
I still haven't fully grasped Kotlin coroutines yet.
Basically I want a coroutine to wait for any previous calls to finish before executing. The following code seems to work. But is it doing what I think it's doing?
private var saveJob: Job? = null
fun save() {
saveJob = someScope.launch {
saveJob?.join()
withContext(Dispatchers.IO) {
// suspending database operation
}
}
}
As far as I can tell, the code is doing what I want. But is it?
回答1:
Keep in mind that the launch
ed code is concurrent to the code outside it. That means that what you wrote has a race condition: the outside code may have already assigned the new job to saveJob
when you try to join()
it, resulting in a deadlock.
I guess what you want is to trigger a save
operation in the background, and the operation itself will pull all the data to save from somewhere else. You probably don't want a queue of save
jobs, just ensure that everything is saved at the point you call save()
. If you called save
a bit earlier and a new save job hasn't yet started, those two calls can be coalesced into a single save
operation.
Furthermore, you say that you have a suspending database operation. Suspending code doesn't belong in the IO
dispatcher, which is there only if you have to perform many blocking operations concurrently.
All told I'd suggest using an actor:
val actor = someScope.actor<Unit>(capacity = CONFLATED) {
// suspending database operation
}
fun save() = someScope.launch {
actor.send(Unit)
}
回答2:
Basically it's not wrong. Although I would recommend just to go imperatively just as you program outside of a coroutine. Saving the response in the variable would ensure that the next line won't execute until the response of the first:
scope.launch(someDispatcher){
val dataFromDelayingCode = getDelayingData()
if(delayingData.isFinished){
}
}
来源:https://stackoverflow.com/questions/58593236/having-coroutine-wait-for-previous-calls