在Akka actor中累积状态的正确模式

编程入门 行业动态 更新时间:2024-10-15 02:33:51
本文介绍了在Akka actor中累积状态的正确模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

问题:

在Akka演员中累积状态的正确模式是什么?

What is the correct pattern for accumulating state in an Akka actor?

上下文:

假设我有一些服务都返回了数据。

Let's say I have a few services that all return data.

class ServiceA extends Actor { def receive = { case _ => sender ! AResponse(100) } } class ServiceB extends Actor { def receive = { case _ => sender ! BResponse("n") } } // ...

我想要一个控制/监督参与者,协调与所有这些服务的对话并跟踪其响应,然后将所有数据的响应发送回原始发送者。

I want to have one controlling/supervising actor that coordinates talking to all these services and keeping track of their responses, then sending a response with all the data back to the original sender.

class Supervisor extends Actor { def receive = { case "begin" => begin case AResponse(id) => ??? case BResponse(letter) => ??? } // end goal: def gotEverything(id: Int, letter: String) = originalSender ! (id, letter) def begin = { ServiceA ! "a" ServiceB ! "b" } }

随着服务响应的到来,怎么办我将所有状态保持在一起吗?据我了解,如果我将AResponse的值分配给 var aResponse:Int ,则var会不断变化,因为接收到不同的消息,而没有我可能会指望等待 BResponse 消息时留下的 var 。

As service responses come in, how do I keep all of that state associated together? As I understand it, if I was to assign the value of AResponse to, say, var aResponse: Int, that var is constantly changing as different messages are being received and it's not possible for me to count on that var staying while I wait for the BResponse message.

我意识到我可以使用 ask 并只嵌套/ flatMap Future ,但是从我阅读的内容来看,这是一个糟糕的模式。

I realize I could use ask and just nest/flatMap Future's, but from what I've read that is a bad pattern. Is there a way to achieve all this without Future's?

推荐答案

因为从不同时从多个线程访问actor,所以可以轻松存储并更改您想要的任何状态。例如,您可以执行以下操作:

Because actors are never accessed from multiple threads simultaneously, you can easily store and mutate any state in them you want. For example, you can do this:

class Supervisor extends Actor { private var originalSender: Option[ActorRef] = None private var id: Option[WhateverId] = None private var letter: Option[WhateverLetter] = None def everythingReceived = id.isDefined && letter.isDefined def receive = { case "begin" => this.originalSender = Some(sender) begin() case AResponse(id) => this.id = Some(id) if (everythingReceived) gotEverything() case BResponse(letter) => this.letter = Some(letter) if (everythingReceived) gotEverything() } // end goal: def gotEverything(): Unit = { originalSender.foreach(_ ! (id.get, letter.get)) originalSender = None id = None letter = None } def begin(): Unit = { ServiceA ! "a" ServiceB ! "b" } }

不过,还有更好的方法。您可以使用没有显式状态变量的参与者来模拟某种状态机。这是通过 become()机制完成的。

There is a better way, however. You can emulate some kind of state machine with actors without explicit state variables. This is done using become() mechanism.

class Supervisor extends Actor { def receive = empty def empty: Receive = { case "begin" => AService ! "a" BService ! "b" context become noResponses(sender) } def noResponses(originalSender: ActorRef): Receive = { case AResponse(id) => context become receivedId(originalSender, id) case BResponse(letter) => context become receivedLetter(originalSender, letter) } def receivedId(originalSender: ActorRef, id: WhateverId): Receive = { case AResponse(id) => context become receivedId(originalSender, id) case BResponse(letter) => gotEverything(originalSender, id, letter) } def receivedLetter(originalSender: ActorRef, letter: WhateverLetter): Receive = { case AResponse(id) => gotEverything(originalSender, id, letter) case BResponse(letter) => context become receivedLetter(originalSender, letter) } // end goal: def gotEverything(originalSender: ActorRef, id: Int, letter: String): Unit = { originalSender ! (id, letter) context become empty } }

这可能会有些冗长,但不包含显式变量;所有状态都隐式包含在 Receive 方法的参数中,并且当需要更新此状态时,仅切换actor的接收函数以反映该新状态。

This may be slightly more verbose, but it does not contain explicit variables; all state is implicitly contained in parameters of Receive methods, and when this state needs to be updated, actor's receive function is just switched to reflect this new state.

请注意,上面的代码非常简单,当可以有很多原始发件人时,它将无法正常工作。在这种情况下,您必须为所有邮件添加一个ID,并使用它们来确定哪些响应属于哪个原始发件人状态,或者您可以为每个原始发件人创建多个参与者。

Note that the above code is very simple and it won't work properly when there can be many "original senders". In that case you'll have to add an id to all messages and use them to determine which responses belong to which "original sender" state or you can create multiple actors, each for every one of the "original senders".

更多推荐

在Akka actor中累积状态的正确模式

本文发布于:2023-11-25 04:47:17,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1628392.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:正确   状态   模式   Akka   actor

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!