简体   繁体   English

让协程等待以前的调用

[英]Having coroutine wait for previous calls

I still haven't fully grasped Kotlin coroutines yet.我还没有完全掌握 Kotlin 协程。

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?但是是吗?

Keep in mind that the launch ed code is concurrent to the code outside it.请记住,已launch的代码与其外部的代码是并发的。 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.这意味着您编写的内容具有竞争条件:当您尝试join()时,外部代码可能已经将新作业分配给saveJob ,从而导致死锁。

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.我猜你想要的是在后台触发save操作,操作本身会提取所有数据以从其他地方保存。 You probably don't want a queue of save jobs, just ensure that everything is saved at the point you call save() .您可能不想要save作业队列,只需确保在您调用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.如果您稍早调用了save并且尚未开始新的保存作业,则可以将这两个调用合并为一个save操作。

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.暂停代码不属于IO调度程序,仅当您必须同时执行许多阻塞操作时才存在。

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)
}

Basically it's not wrong.基本上没有错。 Although I would recommend just to go imperatively just as you program outside of a coroutine.虽然我只推荐 go 就像你在协程之外编程一样。 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){

  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM