问题描述
我还没有完全掌握Kotlin协程.
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?
推荐答案
请记住,launch
ed代码与它外部的代码是并发的.这意味着您编写的内容具有竞争条件:当您尝试对新作业进行join()
时,外部代码可能已经将新作业分配给了saveJob
,从而导致死锁.
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.
我猜您想在后台触发save
操作,该操作本身将提取所有数据以从其他位置保存.您可能不需要队列save
的作业,只需确保在调用save()
的位置保存了所有内容.如果您稍早调用了save
并且尚未开始新的保存作业,则可以将这两个调用合并为一个save
操作.
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.
此外,您说您有一个挂起数据库操作.暂停代码不属于IO
调度程序,只有在您必须同时执行许多 blocking 操作时,该代码才存在.
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)
}
这篇关于让协程等待先前的呼叫的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!