Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala Akka参与者中累积状态的正确模式_Scala_Akka - Fatal编程技术网

Scala Akka参与者中累积状态的正确模式

Scala Akka参与者中累积状态的正确模式,scala,akka,Scala,Akka,问题: 阿克卡演员积累状态的正确模式是什么 上下文: 假设我有一些服务都返回数据 class ServiceA extends Actor { def receive = { case _ => sender ! AResponse(100) } } class ServiceB extends Actor { def receive = { case _ => sender ! BResponse("n") } } // ... 我希望有

问题:

阿克卡演员积累状态的正确模式是什么

上下文:

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

class ServiceA extends Actor {
  def receive = {
    case _ => sender ! AResponse(100)
  }
}

class ServiceB extends Actor {
   def receive = {
     case _ => sender ! BResponse("n")
   }
}

// ...
我希望有一个控制/监督参与者协调与所有这些服务的对话并跟踪它们的响应,然后将包含所有数据的响应发送回原始发送者

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会不断变化,我不可能指望
var
在等待
breresponse
消息时保持不变


我意识到我可以使用
ask
和nest/flatMap
Future
,但从我所读到的来看,这是一种糟糕的模式。有没有一种方法可以在没有Future的情况下实现这一切?

因为参与者永远不会同时从多个线程访问,所以您可以轻松地存储和修改它们中的任何状态。例如,您可以执行以下操作:

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"
  }
}
不过,还有更好的办法。您可以使用没有显式状态变量的参与者来模拟某种状态机。这是使用
been()
机制完成的

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的Receive函数只是切换以反映此新状态


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

我认为Akka的方法是使用每个请求的参与者模式。这样,您就可以在每次收到请求时创建一个新的参与者,而不是找出哪个响应对应于什么。这非常便宜,事实上,每次你问()时都会发生

这些请求处理器(我就是这么叫它们的)通常有简单的响应字段。这只是一个简单的空比较的问题,看看请求是否已经到达


通过此方案,重试/失败也变得容易得多。超时也是如此

为什么
aResponse
会多次更改?您只向
服务A
发送一条消息。你的目标到底是什么?等待您收到
AresResponse
BreResponse
并呼叫
gotEverything
及其值?>>您的目标到底是什么?等到你收到回复和回复,然后打电话给gotEverything及其价值观?是的,您可以将响应存储在带有标识符或actor ref的列表中。下面是actor per request的示例,并解释了为什么它们也使用tell而不是ask。