Игнорирование предложений к сопрограммным каналам после закрытия - PullRequest
0 голосов
/ 15 января 2019

Есть ли хороший способ, чтобы каналы игнорировали предложения после закрытия без исключения?

В настоящее время, похоже, что только попытка catch будет работать, так как isClosedForSend не является атомарным.

Или есть проблема, если я вообще никогда не закрываю канал? Для моего конкретного случая использования я использую каналы в качестве альтернативы Android-данным (поскольку мне не нужны какие-либо преимущества, кроме отправки значений из любого потока и прослушивания из основного потока). В этом случае я мог бы прослушивать канал через производителя, который отправляет значения только тогда, когда я этого хочу, и просто игнорировать все остальные входы.

В идеале, у меня было бы решение, в котором ReceiveChannel все еще может закончить прослушивание, но когда SendChannel никогда не завершится с ошибкой, когда будет предложено новое значение.

Ответы [ 2 ]

0 голосов
/ 17 января 2019

В итоге я опубликовал проблему в репо, и решение было использовать BroadcastChannel. Вы можете создать новый ReceiveChannel - openSubscription, закрытие которого не приведет к закрытию SendChannel.

Это более точно отражает RxJava PublishSubject

0 голосов
/ 16 января 2019

Каналы выбрасывают это исключение по схеме , как средство правильной связи.

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

private suspend fun <E> Channel<E>.sendOrNothing(e: E) {
    try {
        this.send(e)
    }
    catch (closedException: ClosedSendChannelException) {
        println("It's fine")
    }
}

Вы можете проверить это с помощью следующего кода:

val channel = Channel<Int>(capacity = 3)
    launch {

        try {
            for (i in 1..10) {
                channel.sendOrNothing(i)
                delay(50)
                if (i == 5) {
                    channel.close()
                }
            }

            println("Done")
        }
        catch (e: Exception) {
            e.printStackTrace()
        }
        finally {
            println("Finally")
        }
    }

    launch {
        for (c in channel) {
            println(c)
            delay(300)
        }
    }

Как вы заметите, производитель начнет печатать "Все хорошо", так как канал закрыт, но потребитель все равно сможет прочитать первые 5 значений.

Относительно вашего второго вопроса: это зависит.

Каналы не имеют таких больших накладных расходов, как и приостановленные сопрограммы. Но утечка - это утечка, вы знаете.

...