Как ждать завершения всех сопрограмм? - PullRequest
1 голос
/ 29 апреля 2019

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

Мой упрощенный код выглядит так:

fun hello() {
    for (i in 0..100) {
        println("hello")
    }
}

fun main(args: Array<String>) {
    val job = GlobalScope.launch { hello() } //launch parallel 
    GlobalScope.launch { job.join() }  //try to wait for job to finish
    print("done")
}

Проблема в том, что job.join() должен находиться в сопрограмме, основная строка выполнения откладывается до "выполнено", поэтому вывод выглядит следующим образом:

donehello
hello
hello
hello

Я хочу дождаться завершения задания, например, используя sync.WaitGroup в Go. Поэтому мой вывод будет выглядеть детерминистически так:

hello
hello
hello
hello
...
done

Как мне это сделать?

Ответы [ 2 ]

2 голосов
/ 29 апреля 2019

На самом деле для вашего образца job.join() - это способ гарантировать, что в этот момент он ожидает, пока задание не будет завершено. К сожалению, вы снова упаковали его в GlobalScope.launch, что просто помещает это ожидание в фоновый поток. Поэтому он достигает done раньше, чем вы ожидаете, и на моей машине он даже не печатал hello (но мог).

Я полагаю, вы использовали launch, потому что join может вызываться только из сопрограммы или другой функции приостановки? Для вашего примера было бы достаточно просто добавить suspend к main, например ::

suspend fun main() {
  val job = GlobalScope.launch { hello() }
  job.join()
  print("done")
}

или вы могли бы использовать runBlocking и обернуть ею main, например ::

fun main() = runBlocking {
  val job = launch { hello() }      
  job.join()
  print("done")
}

Теперь отказ от ответственности ... вы можете обратиться к следующим источникам, прежде чем продолжить (если вы этого еще не сделали):

  1. Основы сопрограмм
  2. Причина, по которой следует избегать GlobalScope от Роман Елизаров
  3. Параллельные сопрограммы - параллелизм не параллелизм от @ s1m0nw1
0 голосов
/ 29 апреля 2019

Почему бы вам не распечатать свое сообщение внутри сопрограммы? Вы можете достичь того, что вы ищете, сделав это:

GlobalScope.launch {
    hello()
    print("done")
}

Или вы можете запустить сопрограмму и заблокировать ее, пока она не закончится, даже если это как бы побеждает назначение сопрограммы:

runBlocking { GlobalScope.launch { hello() }
print("done")
...