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

Рассмотрим следующий код:

import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
    val channel = Channel<String>()
    launch {
        channel.send("A1")
        channel.send("A2")
        log("A done")
    }
    launch {
        channel.send("B1")
        log("B done")
    }
    launch {
        for (x in channel) {
            log(x)
        }
    }
}

fun log(message: Any?) {
    println("[${Thread.currentThread().name}] $message")
}

Исходная версия имеет такую ​​сопрограмму-получатель:

launch {
        repeat(3) {
            val x = channel.receive()
            log(x)
        }
    }

Она ожидает только 3 сообщения в канале. Если я изменю его на первую версию, мне нужно закрыть канал после того, как все сопрограммы производителя будут выполнены. Как я могу это сделать?

1 Ответ

3 голосов
/ 29 мая 2020

Возможное решение - создать задание, которое будет ждать, пока все channel.send() завершат sh, и вызывать channel.close() в invokeOnCompletion этого задания:

import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.*

fun main() = runBlocking<Unit> {
    val channel = Channel<String>()
    launch {
      launch {
          channel.send("A1")
          channel.send("A2")
          log("A done")
      }
      launch {
          channel.send("B1")
          log("B done")
      }
    }.invokeOnCompletion {
        channel.close()
    }
    launch {
        for (x in channel) {
            log(x)
        }
    }
}

fun log(message: Any?) {
    println("[${Thread.currentThread().name}] $message")
}
...