Size: a a a

Kotlin Community

2020 July 08

AN

Alexander Nozik in Kotlin Community
М R
Привет!
Можете помочь? Я в тупик зашёл. Имеется вот такой пример.
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)

fun main() = runBlocking {
   val channel = BroadcastChannel<String>(1)
   for (i in 0..20) {
       println("iteration ${i + 1} start")
       val job = scope.launch {
           channel.openSubscription()
               .receiveAsFlow()
               .collect { println("receive $it") }
       }

       scope.launch(Dispatchers.IO) {
           channel.send("$i")
       }
       delay(200)
       job.cancel()
   }
   return@runBlocking
}


Но вот println("receive $it") печатает только первые два значения, и я не могу понять, в чем причина.  Может кто-то сможет объяснить
Ну для начала у вас замешаны два скоупа - один от runBlocking, второй от scope. Надо все-таки использовать или то, или другое или наследовать одно от другого. Дальше, не понятна логика, по которой вы все отменяете. Вполне может быть, что на разогреве виртуальной машины, вы и не успеваете отослать больше двух значений. Зачем там вообще отмена по времени?
источник

AN

Alexander Nozik in Kotlin Community
Замес скоупов в данном случае не должен влиять, но это указатель на то, что вы не понимаете, что делаете
источник

МR

М R in Kotlin Community
Alexander Nozik
Ну для начала у вас замешаны два скоупа - один от runBlocking, второй от scope. Надо все-таки использовать или то, или другое или наследовать одно от другого. Дальше, не понятна логика, по которой вы все отменяете. Вполне может быть, что на разогреве виртуальной машины, вы и не успеваете отослать больше двух значений. Зачем там вообще отмена по времени?
это просто пример, чтобы воспроизвести проблему.
Отмена по таймеру тоже для примера, чтобы "дождаться" отправки.
В оригинале подписка происходит в одном скоупе, а отправка в другом. Но оригинал - это большое приложение, поэтому воспроизвёл приближено.
источник

AN

Alexander Nozik in Kotlin Community
М R
это просто пример, чтобы воспроизвести проблему.
Отмена по таймеру тоже для примера, чтобы "дождаться" отправки.
В оригинале подписка происходит в одном скоупе, а отправка в другом. Но оригинал - это большое приложение, поэтому воспроизвёл приближено.
А если увеличить время таймера - поможет?
источник

МR

М R in Kotlin Community
Alexander Nozik
А если увеличить время таймера - поможет?
нет
источник

AN

Alexander Nozik in Kotlin Community
А у вас так и задумано, что 20 подписок?
источник

МR

М R in Kotlin Community
не 20 конечно, но точно больше 2х
источник

AN

Alexander Nozik in Kotlin Community
Похоже на дедлок
источник

МR

М R in Kotlin Community
похоже, но я не могу его объяснить
источник

AN

Alexander Nozik in Kotlin Community
channel.send("$i") суспендидтся пока канал не вычитается, а канал не читается пока сенд не выполнится. Разнесите подписки и оптавки в разные циклы
источник

A

Aleksandr in Kotlin Community
а после job.cancel(), channel не закрывается?
источник

AN

Alexander Nozik in Kotlin Community
Aleksandr
а после job.cancel(), channel не закрывается?
нет, не должен
источник

A

Aleksandr in Kotlin Community
а если проверить?
источник

AN

Alexander Nozik in Kotlin Community
Супервайзер кстати тоже в таком примере не нужен, потому что отмена не роняет родителя
источник

AN

Alexander Nozik in Kotlin Community
Aleksandr
а если проверить?
А чего проверять? Тем более, что все должно проекрутиться до этой отмены
источник

L

L in Kotlin Community
Там же отмена в цикле идёт прям, и если заюзать ReceiveChannel.cancel() то все будет работать
источник

AN

Alexander Nozik in Kotlin Community
L
Там же отмена в цикле идёт прям, и если заюзать ReceiveChannel.cancel() то все будет работать
А кстати да, там пока первый не отменится, второй не стартует. А оменяется только подписка, но не send
источник

L

L in Kotlin Community
В том то и дело что даже подписка не отменяется, а просто Job cancell’ится, в доках к openSubscription сказано что для отписки нужно делать cancel к ReceiveChannel который возращается при открытии подписки
источник

AN

Alexander Nozik in Kotlin Community
L
В том то и дело что даже подписка не отменяется, а просто Job cancell’ится, в доках к openSubscription сказано что для отписки нужно делать cancel к ReceiveChannel который возращается при открытии подписки
подписка должна отмениться потому что отменятся родительский скоуп подписки, но тут я не на 100% уверен.
источник

A

Aleksandr in Kotlin Community
если у канала выставишь capacity 20, то будет работать
источник