Как заставить сопрограммы работать в последовательности от внешнего вызова - PullRequest
2 голосов
/ 01 апреля 2019

Я действительно новичок в сопрограммах и о том, как это работает, я много об этом читал, но не могу понять, как или смогу ли я достичь своей конечной цели.

Я постараюсь объяснить как можно подробнее. В любом случае, вот моя цель:

Ensure that coroutines run sequentially when a method that has said coroutine is called.

Я создал тест, который соответствует тому, что я хотел бы получить:

class TestCoroutines {

  @Test
  fun test() {
    println("Starting...")

    runSequentially("A")
    runSequentially("B")

    Thread.sleep(1000)
  }

  fun runSequentially(testCase: String) {
    GlobalScope.launch {
      println("Running test $testCase")
      println("Test $testCase ended")
    }
  }
}

Важное примечание: Я не могу контролировать, сколько раз кто-то будет вызывать функцию runSequentially. Но я хочу гарантировать, что он будет вызываться по порядку.

Этот тест запускает следующие выходные данные:

Starting...
Running test B
Running test A
Test A ended
Test B ended

Starting...
Running test A
Running test B
Test B ended
Test A ended

This is the output I want to achieve :
Starting...     
Running test A
Test A ended
Running test B
Test B ended

Мне кажется, я понимаю, почему это происходит: каждый раз, когда я звоню runSequentially, я создаю новое задание, в котором оно выполняется и работает асинхронно.

Можно ли с сопрограммами гарантировать, что они будут работать только после предыдущего (если он запущен) финиша, когда у нас нет контроля над тем, сколько раз эта сопрограмма вызывается?

1 Ответ

3 голосов
/ 01 апреля 2019

То, что вы ищете, - это комбинация очереди, которая заказывает запросы, и работника, который их обслуживает.Короче, вам нужен актер :

private val testCaseChannel = GlobalScope.actor<String>(
        capacity = Channel.UNLIMITED
) {
    for (testCase in channel) {
        println("Running test $testCase")
        println("Test $testCase ended")
    }
}

fun runSequentially(testCase: String) = testCaseChannel.sendBlocking(testCase)
...