Scala 来自路由器的消息到达时的Akka路由器增量计数器
我一直在努力指望每一次成功的导入。但这里有一个问题-如果路由器从其父节点接收到消息,计数器会工作,但是如果我试图从其子节点发送消息,它会接收消息,但不会更新超出范围的全局变量。 我知道这听起来很复杂。让我给你看看代码。 这是路由器Scala 来自路由器的消息到达时的Akka路由器增量计数器,scala,akka,Scala,Akka,我一直在努力指望每一次成功的导入。但这里有一个问题-如果路由器从其父节点接收到消息,计数器会工作,但是如果我试图从其子节点发送消息,它会接收消息,但不会更新超出范围的全局变量。 我知道这听起来很复杂。让我给你看看代码。 这是路由器 class Watcher(size: Int) extends Actor { var router = { val routees = Vector.fill(size) { val w = context
class Watcher(size: Int) extends Actor {
var router = {
val routees = Vector.fill(size) {
val w = context.actorOf(
Props[Worker]
)
context.watch(w)
ActorRefRoutee(w)
}
Router(RoundRobinRoutingLogic(), routees)
}
var sent = 0
override def supervisorStrategy(): SupervisorStrategy = OneForOneStrategy(maxNrOfRetries = 100) {
case _: DocumentNotFoundException => {
Resume
}
case _: Exception => Escalate
}
override def receive: Receive = {
case container: MessageContainer =>
router.route(container, sender)
case Success =>
sent += 1
case GetValue =>
sender ! sent
case Terminated(a) =>
router.removeRoutee(a)
val w = context.actorOf(Props[Worker])
context.watch(w)
router = router.addRoutee(w)
case undef =>
println(s"${this.getClass} received undefinable message: $undef")
}
}
工人来了
class Worker() extends Actor with ActorLogging {
var messages = Seq[MessageContainer]()
var received = 0
override def receive: Receive = {
case container: MessageContainer =>
try {
importMessage(container.message, container.repo)
context.parent ! Success
} catch {
case e: Exception =>
throw e
}
case e: Error =>
log.info(s"Error occurred $e")
sender ! e
case undef => println(s"${this.getClass} received undefinable message: $undef")
}
}
那么是主管?GetValue
我得到0,但假设有1000。最奇怪的是,当我在case Success=>上的断点处调试它时,…
每次新消息到达时,该值都会递增。但是主管?GetValue仍然返回0
让我们假设我想依靠case-container:MessageContainer=>…
,它将神奇地工作;我会得到理想的数字,但它不能显示我是否真的导入了任何东西。发生什么事了
下面是测试用例
@Test
def testRouter(): Unit = {
val system = ActorSystem("RouterTestSystem")
// val serv = AddressFromURIString("akka.tcp://master@host:1334")
val supervisor = system.actorOf(Props(new Watcher(20)))//.withDeploy(akka.actor.Deploy(scope = RemoteScope(serv))))
val repo = coreSession.getRepositoryName
val containers = (0 until num)
.map(_ => MessageContainer(MessageFactory.generate("/"), repo))
val watch = Stopwatch.createStarted()
(0 until num).par
.foreach( i => {
supervisor ! containers.apply(i)
})
implicit val timeout = Timeout(60 seconds)
val future = supervisor ? GetValue
val result = Await.result(future, timeout.duration).asInstanceOf[Int]
val speed = result / (watch.elapsed(TimeUnit.MILLISECONDS) / 1000.0)
println(f"Import speed: $speed%.2f")
assertEquals(num, result)
}
你能详细解释一下吗。为什么会这样?为什么只在收到孩子们的信息时才这样做?另一种方法 嗯。。。在您尚未共享的代码部分中可能隐藏着许多潜在问题。但是,为了讨论这个问题,我假设其他一切都很好,我们只讨论共享代码的问题
现在,让我解释一下演员。简单地说,每个参与者都有一个邮箱(它按接收顺序保存消息),并按接收顺序逐个处理消息。由于邮箱的使用方式类似于队列
,因此在本讨论中将其称为队列
还有。。。我不知道这个容器。apply(I)
将返回什么。。。因此,我将引用该容器的返回值。apply(1)
作为MessageContainer\uu 1
在测试运行程序中,您首先创建了观察者的一个实例
val supervisor = system.actorOf(Props(new Watcher(20)))
现在,假设您正在将这些2条消息(num=2)
发送给supervisor
所以主管的邮箱看起来像
Queue(MessageContainer__0, MessageContainer__1)
然后再向它发送另一条消息GetValue
,使邮箱看起来像
Queue(MessageContainer__0, MessageContainer__1, GetValue)
Queue(MessageContainer__1, GetValue, Success)
Queue(GetValue, Success, Success)
现在,演员将处理第一条消息并将其传递给工人,邮箱将如下所示:
Queue(MessageContainer__1, GetValue)
现在,即使您的工作人员以极快的速度发送回复,邮箱也会是这样
Queue(MessageContainer__0, MessageContainer__1, GetValue)
Queue(MessageContainer__1, GetValue, Success)
Queue(GetValue, Success, Success)
现在,由于您的工作人员以超快的速度即时回复成功
,因此传递第二个MessageContainer后的状态如下:
Queue(MessageContainer__0, MessageContainer__1, GetValue)
Queue(MessageContainer__1, GetValue, Success)
Queue(GetValue, Success, Success)
而且。。。这是你问题的根源。无论您的员工速度有多快,主管在任何成功
消息之前都会看到GetValue
消息
因此,它将处理GetValue
,并使用当前值sent
进行回复,当前值为0。那么,如何获取到达的消息量呢。首先,我想到的是创建一个等待循环。。。但是,我认为它不会做得很漂亮。