Наличие сопрограммы ждать предыдущих звонков - PullRequest
1 голос
/ 28 октября 2019

Я до сих пор не полностью понял сопрограммы Kotlin.

По сути, я хочу, чтобы сопрограмма ожидала завершения любых предыдущих вызовов перед выполнением. Следующий код, кажется, работает. Но делает ли он то, что мне кажется?

private var saveJob: Job? = null

fun save() {
    saveJob = someScope.launch {
        saveJob?.join()
        withContext(Dispatchers.IO) {
            // suspending database operation
        }
    }
}

Насколько я могу судить, код делает то, что я хочу. Но так ли это?

Ответы [ 2 ]

2 голосов
/ 28 октября 2019

Имейте в виду, что код launch ed совпадает с кодом вне его. Это означает, что то, что вы написали, имеет условие гонки: внешний код, возможно, уже назначил новое задание на saveJob, когда вы пытаетесь join() его, что приводит к тупику.

Я думаю, что вы хотитеэто вызвать save операцию в фоновом режиме, и сама операция извлечет все данные для сохранения из другого места. Возможно, вам не нужна очередь из save заданий, просто убедитесь, что все сохранено в точке, которую вы называете save(). Если вы позвонили save чуть раньше, а новое задание сохранения еще не началось, эти два вызова можно объединить в одну операцию save.

Кроме того, вы говорите, что у вас есть приостановка операция базы данных. Приостановленный код не входит в диспетчер IO, который есть только в том случае, если вам нужно одновременно выполнять много операций , блокирующих .

Все, что я предложил бы использовать актера:

val actor = someScope.actor<Unit>(capacity = CONFLATED) {
    // suspending database operation
}

fun save() = someScope.launch {
    actor.send(Unit)
}
1 голос
/ 28 октября 2019

В принципе, это не так. Хотя я бы порекомендовал просто идти так же, как вы программируете за пределами сопрограммы. Сохранение ответа в переменной гарантирует, что следующая строка не будет выполняться до ответа первой:

scope.launch(someDispatcher){
  val dataFromDelayingCode = getDelayingData()
  if(delayingData.isFinished){

  }
}
...