当容量小于消息数时,Kotlin actors进入死锁

当容量小于消息数时,Kotlin actors进入死锁,kotlin,Kotlin,我想把阿克卡演员和科特林演员作为基准。对kotlin有了一些基本的了解,我试着用乒乓球做了一个简单的测试,结果程序卡住了。只有当我使容量大小和消息数量相同时,它才进展到完成。据我理解,两个行动者都应继续开展工作,而不应依赖能力 import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.channels.SendChannel im

我想把阿克卡演员和科特林演员作为基准。对kotlin有了一些基本的了解,我试着用乒乓球做了一个简单的测试,结果程序卡住了。只有当我使容量大小和消息数量相同时,它才进展到完成。据我理解,两个行动者都应继续开展工作,而不应依赖能力

import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.channels.actor
import kotlinx.coroutines.runBlocking

sealed class Message
class Ping(val replyTo: SendChannel<Message>) : Message()
object Pong : Message()

object Start : Message()

fun CoroutineScope.PingActor() = actor<Message>(capacity = 10) {
    for (msg in channel) { 
        when (msg) {
            is Ping ->
                msg.replyTo.send(Pong)
        }
    }
}

fun CoroutineScope.PongActor(pinger: SendChannel<Message>, count: Int, done: CompletableDeferred<Unit>) =
    actor<Message> (capacity = 10){
        var counter = count 

        for (msg in channel) { 
            when (msg) {
                is Start ->
                    for (i in 1..count) {
                        pinger.send(Ping(this.channel))
                    }

                is Pong -> {
                    counter -= 1
                    if (counter == 0) {
                        done.complete(Unit)
                    }
                }
            }

        }
    }

fun main() = runBlocking<Unit> {

    val response = CompletableDeferred<Unit>()
    val pinger = PingActor() 
    val ponger = PongActor(pinger, 100, response) 
    val startTime = System.nanoTime()

    ponger.send(Start)
    response.await()

    println("total time taken is ${System.nanoTime() - startTime}")
    pinger.close() 
    ponger.close()
}
导入kotlinx.coroutines.CompletableDeferred
导入kotlinx.coroutines.CoroutineScope
导入kotlinx.coroutines.channels.SendChannel
导入kotlinx.coroutines.channels.actor
导入kotlinx.coroutines.runBlocking
密封类消息
类Ping(val replyTo:SendChannel):Message()
对象Pong:Message()
对象开始:消息()
fun CoroutineScope.PingActor()=参与者(容量=10){
对于(通道中的msg){
何时(味精){
是Ping->
msg.replyTo.send(Pong)
}
}
}
PongActor(pinger:SendChannel,count:Int,done:CompletableDeferred)=
演员(容量=10){
变量计数器=计数
对于(通道中的msg){
何时(味精){
是开始->
对于(1.计数中的i){
pinger.send(Ping(this.channel))
}
是庞->{
计数器-=1
如果(计数器==0){
完成。完成(单位)
}
}
}
}
}
fun main()=运行阻塞{
val响应=CompletableDeferred()
val pinger=PingActor()
val ponger=PongActor(pinger,100,响应)
val startTime=System.nanoTime()
ponger.send(启动)
response.wait()
println(“所花费的总时间为${System.nanoTime()-startTime}”)
pinger.close()
ponger.close()
}
只有当我使容量大小和消息数量相同时,它才进展到完成

您可以检查50个容量(对于两个演员)是否足够。让我们看看10会发生什么:

  • pinger
    接收
    Start
    消息
  • pinger
    尝试向
    ponger
    发送100条消息。发送10个,第11个块,直到队列中有更多空间
  • ponger
    处理消息并发送10条回复
  • pinger
    现在可以再发送10条消息
  • ponger
    尝试处理第11次
    Ping
    ,但在发送回复时会被阻止,因为
    pinger
    的邮箱中有10条消息

  • 请注意,
    pinger
    无法处理回复,因为它仍在处理
    Start
    消息

    谢谢。因此,如果我不能提前知道消息的数量,那么我需要使用无限容量,或者改变逻辑。例如,在普通乒乓球比赛中,你只会立即发送第一个乒乓球,其余的都是回复乒乓球。这样你就不会遇到这个问题了。