channel.asFlux()在高并发情况下似乎导致死锁

时间:2019-06-30 16:45:22

标签: kotlin kotlin-coroutines

好吧,我已经编辑了整个问题,并制作了两个版本的代码,这似乎更有趣。 这里有2个功能,一个导致死锁,另一个没有。 问题似乎出在channel.asFlux()转换内部,但我不知道避免这种锁定的最佳实践是什么。

谢谢你, 弗朗切斯科


    @Test
    @Disabled("investigating..")
    fun tt() = runBlocking<Unit>{
        (0..3000).map { async {
            //noDeadLock()
            yesDeadLock()
        }}.forEach { it.await()}
    }


    val thPool = newSingleThreadContext("single")
    suspend fun yesDeadLock(){
        withContext(Dispatchers.IO){ DEADLOCK
            var channel = Channel<Int>(Channel.RENDEZVOUS)
            val producer =
                launch(newSingleThreadContext("nconte")){
                    while (isActive  && !channel.isClosedForSend && !channel.isClosedForReceive ){
                        try{
                            channel.send(1)
                        }catch (t:Throwable){
                        }
                    }
                }

            withContext(Dispatchers.Default){ 
            // withContext(thPool){  // <<-- with any other context, even a single thread, this long cause deadlocks
                channel.asFlux()
                    .publishOn(Schedulers.elastic(),1)
                    .doFinally {  producer.cancel() }
                    .limitRate(1)
                    .take(30)
                    .blockLast()
            }
            1
        }
    }

    suspend fun noDeadLock(){
        withContext(Dispatchers.Default){ 
            var channel = Channel<Int>(Channel.RENDEZVOUS)
            val producer =
                launch(newSingleThreadContext("nconte")){
                    while (isActive  && !channel.isClosedForSend && !channel.isClosedForReceive ){
                        try{
                            channel.send(1)
                        }catch (t:Throwable){
                        }
                    }
                }

            withContext(Dispatchers.IO){ 
                channel.asFlux()
                    .publishOn(Schedulers.elastic(),1)
                    .doFinally {  producer.cancel() }
                    .limitRate(1)
                    .take(30)
                    .blockLast()
            }
            1
        }
    }

0 个答案:

没有答案