Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/16.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 在启动主逻辑之前处理参与者需求_Scala_Akka_Actor_Akka Typed - Fatal编程技术网

Scala 在启动主逻辑之前处理参与者需求

Scala 在启动主逻辑之前处理参与者需求,scala,akka,actor,akka-typed,Scala,Akka,Actor,Akka Typed,请看下图: 在这个场景中,我们有两个经理。ManagerA和ManagerB,都是由同一位父亲同时产生的。ManagerB还立即生成3个子项,开始处理某些数据。当worker完成处理并得到结果时,他会将结果返回给ManagerB ManagerB然后通知ManagerA他有一个名为B1 ready的对象。然后,ManagerA告诉A1、A2和A3 B1已准备就绪,并将其传递给他们。但是只有A1和A2需要B1,所以他们保留它,A3丢弃消息。A1有所有的需求,现在就开始执行他的主逻辑,因为他有B1

请看下图:

在这个场景中,我们有两个经理。ManagerA和ManagerB,都是由同一位父亲同时产生的。ManagerB还立即生成3个子项,开始处理某些数据。当worker完成处理并得到结果时,他会将结果返回给ManagerB

ManagerB然后通知ManagerA他有一个名为B1 ready的对象。然后,ManagerA告诉A1、A2和A3 B1已准备就绪,并将其传递给他们。但是只有A1和A2需要B1,所以他们保留它,A3丢弃消息。A1有所有的需求,现在就开始执行他的主逻辑,因为他有B1,所以他这样做了。同时A2还需要B2,A3需要B3


如何在Scala中使用akka参与者实现这样的逻辑?我很难找到一种方法以功能的方式保存需求,并在最终满足所有需求时开始执行。

我将使用的基本思想是在一个case类中编码状态,该类至少包含一组需求和一个键为a(非严格)的映射要求的子集,其值是B工作人员的结果,例如对于
A1
,我们可能有:

requirements = Set("B1")
received = Map("B1" -> B1Result(...))
参与者的行为是其状态的函数:改变状态的消息会改变行为

更具体地说,您可以执行以下操作:

object AWorker {
  type BResult = Any  // BResult would probably defined elsewhere, I'm aliasing Any for brevity

  type Action = (ActorContext[Command], Map[String, BResult]) => Unit

  sealed trait Command

  case class RequirementsAndDo(
    requirements: Set[String],
    action: Action,
    replyTo: Option[ActorRef[Reply]]
  ) extends Reply

  case class Completed(key: String, value: BResult, replyTo: Option[ActorRef[Reply]]) extends Reply

  sealed trait Reply
  case object Ack extends Reply

  def apply(): Behavior[Command] = withState(State())

  private[AWorker] case class State(
    requirements: Set[String] = Set.empty,
    received: Map[String, BResult] = Map.empty,
    whenRequirementsMet: Option[Action] = None
  ) {
    def updateRequirements(req: Set[String], f: Option[Action]): State = {
      // For now, start anew...
      State(req)
    }

    def completeRequirement(req: String, v: BResult): State =
      copy(received = received.updated(req, v))

    def checkAndPerform(ctx: ActorContext[Command]): State = {
      if (requirements.diff(received.keySet).isEmpty) {
        whenRequirementsMet.foreach { a =>
          a(ctx, received)
        }
        State()
      } else this
  }

  private def withState(state: State): Behavior[Command] =
    Behaviors.receive { (context, msg) =>
      msg match {
        case RequirementsAndDo(req, action, replyTo) =>
          val nextState = state.updateRequirements(req, action)
          replyTo.foreach(_ ! Ack)
          withState(nextState)
        case Completed(key, value, replyTo) =>
          val intermediateState = state.completeRequirement(key, value)
          replyTo.foreach(_ ! Ack)
          withState(intermediateState.checkAndPerform(context))
      }
    }
}

通过让
State
上的方法返回效果和新状态的元组,您可以使这一点更加灵活,但是这个IMO接近最佳实用功能。请特别注意,这鼓励将域效果(例如工作完成前后)与实现协议效果(例如回复)分开。

Nice!玩了一会儿,我明白了要点。谢谢