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