斯卡拉 – 阿卡消息传递时间
我正在与
Scala和Akka一起进行人工生命模拟,到目前为止,我对两者都非常满意.我有一些时间问题,但我无法解释.
目前,我模拟的每只动物都是一对演员(动物大脑).通常,这两个演员轮流(动物将传感器输入发送到大脑,等待结果,作用于它并重新开始).然而,不时地,动物需要彼此互动以互相吃饭或繁殖. 对我来说奇怪的一件事是时机.事实证明,从一只动物向另一只动物发送信息比从动物发送到大脑要慢很多(大约100倍).这使得我的可怜的食肉动物和性活跃的动物处于劣势,而不是素食者和无性动物(免责声明:我自己也吃素,但我认为成为素食主义者的理由比在尝试捕食时陷入困境更好. ). 我提取了一个演示问题的最小代码片段: package edu.blindworld.test import java.util.concurrent.TimeUnit import akka.actor.{ActorRef,ActorSystem,Props,Actor} import akka.pattern.ask import akka.util.Timeout import scala.concurrent.Await import scala.concurrent.duration.Duration import scala.util.Random class Animal extends Actor { val brain = context.actorOf(Props(classOf[Brain])) var animals: Option[List[ActorRef]] = None var brainCount = 0 var brainRequestStartTime = 0L var brainNanos = 0L var peerCount = 0 var peerRequestStartTime = 0L var peerNanos = 0L override def receive = { case Go(all) => animals = Some(all) performLoop() case BrainResponse => brainNanos += (System.nanoTime() - brainRequestStartTime) brainCount += 1 // Animal interactions are rare if (Random.nextDouble() < 0.01) { // Send a ping to a random other one (or ourselves). Defer our own loop val randomOther = animals.get(Random.nextInt(animals.get.length)) peerRequestStartTime = System.nanoTime() randomOther ! PeerRequest } else { performLoop() } case PeerResponse => peerNanos += (System.nanoTime() - peerRequestStartTime) peerCount += 1 performLoop() case PeerRequest => sender() ! PeerResponse case Stop => sender() ! StopResult(brainCount,brainNanos,peerCount,peerNanos) context.stop(brain) context.stop(self) } def performLoop() = { brain ! BrainRequest brainRequestStartTime = System.nanoTime() } } class Brain extends Actor { override def receive = { case BrainRequest => sender() ! BrainResponse } } case class Go(animals: List[ActorRef]) case object Stop case class StopResult(brainCount: Int,brainNanos: Long,peerCount: Int,peerNanos: Long) case object BrainRequest case object BrainResponse case object PeerRequest case object PeerResponse object ActorTest extends App { println("Sampling...") val system = ActorSystem("Test") val animals = (0 until 50).map(i => system.actorOf(Props(classOf[Animal]))).toList animals.foreach(_ ! Go(animals)) Thread.sleep(5000) implicit val timeout = Timeout(5,TimeUnit.SECONDS) val futureStats = animals.map(_.ask(Stop).mapTo[StopResult]) val stats = futureStats.map(Await.result(_,Duration(5,TimeUnit.SECONDS))) val brainCount = stats.foldLeft(0)(_ + _.brainCount) val brainNanos = stats.foldLeft(0L)(_ + _.brainNanos) val peerCount = stats.foldLeft(0)(_ + _.peerCount) val peerNanos = stats.foldLeft(0L)(_ + _.peerNanos) println("Average time for brain request: " + (brainNanos / brainCount) / 1000000.0 + "ms (sampled from " + brainCount + " requests)") println("Average time for peer pings: " + (peerNanos / peerCount) / 1000000.0 + "ms (sampled from " + peerCount + " requests)") system.shutdown() } 这就是这里发生的事情: >我正在创造50对动物/大脑演员 在我的双核i7上,我看到这些数字:
因此对同行的ping比对大脑的要求慢165倍.我一直在尝试很多东西来解决这个问题(例如优先邮箱和热身JIT),但还是无法弄清楚发生了什么.有没有人有想法? 解决方法
我认为你应该使用ask模式来处理消息.在你的代码中,BrainRequest被发送给大脑演员,然后它发送回BrainResponse.问题出在这里. BrainResponse不是BrainRequest的回应.也许这是以前的BrainRequest的回应.
以下代码使用ask模式,perf结果几乎相同. package edu.blindworld.test import java.util.concurrent.TimeUnit import akka.actor.{ActorRef,Actor} import akka.pattern.ask import akka.util.Timeout import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Await import scala.concurrent.duration._ import scala.util.Random class Animal extends Actor { val brain = context.actorOf(Props(classOf[Brain])) var animals: Option[List[ActorRef]] = None var brainCount = 0 var brainRequestStartTime = 0L var brainNanos = 0L var peerCount = 0 var peerRequestStartTime = 0L var peerNanos = 0L override def receive = { case Go(all) => animals = Some(all) performLoop() case PeerRequest => sender() ! PeerResponse case Stop => sender() ! StopResult(brainCount,peerNanos) context.stop(brain) context.stop(self) } def performLoop(): Unit = { brainRequestStartTime = System.nanoTime() brain.ask(BrainRequest)(10.millis) onSuccess { case _ => brainNanos += (System.nanoTime() - brainRequestStartTime) brainCount += 1 // Animal interactions are rare if (Random.nextDouble() < 0.01) { // Send a ping to a random other one (or ourselves). Defer our own loop val randomOther = animals.get(Random.nextInt(animals.get.length)) peerRequestStartTime = System.nanoTime() randomOther.ask(PeerRequest)(10.millis) onSuccess { case _ => peerNanos += (System.nanoTime() - peerRequestStartTime) peerCount += 1 performLoop() } } else { performLoop() } } } } class Brain extends Actor { override def receive = { case BrainRequest => sender() ! BrainResponse } } case class Go(animals: List[ActorRef]) case object Stop case class StopResult(brainCount: Int,TimeUnit.SECONDS))) val brainCount = stats.foldLeft(0)(_ + _.brainCount) val brainNanos = stats.foldLeft(0L)(_ + _.brainNanos) val peerCount = stats.foldLeft(0)(_ + _.peerCount) val peerNanos = stats.foldLeft(0L)(_ + _.peerNanos) println("Average time for brain request: " + (brainNanos / brainCount) / 1000000.0 + "ms (sampled from " + brainCount + " requests)") println("Average time for peer pings: " + (peerNanos / peerCount) / 1000000.0 + "ms (sampled from " + peerCount + " requests)") system.shutdown() } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |