我正在尝试弄清楚如何使用父级收到的多个结果并将其发送给父级。
我对akka的基本知识掌握得很好,而且我知道如何传递消息并收到一个回复。当我需要将两个答复合并为一个结果(然后将该结果传递)时,我迷路了。
例如: 我要同时添加1,2,3,4。因此,我向一个孩子发送了包含1和2的消息,向另一个孩子发送了包含3和4的消息。他们将各自的数字相加,然后向父母发送回信,理想情况下,父母会相加2个结果。
答案 0 :(得分:0)
假设akka
和java
有点相似,您可以这样做
firstMethod(arguments) + secondMethod(arguments)
,因为您要添加结果。 (根据返回值得出)
答案 1 :(得分:0)
您可以在父演员中保留一个簿记参数,因此在scala代码中,将是这样的:
object SumAggregationWorker {
def props: Props = Props[SumAggregationWorker]
case class ReceivedValue(value: Double)
}
class SumAggregationWorker extends Actor {
var totalSum: Int = 0
override def receive: Receive = {
case ReceivedValue(value) =>
totalSum += value
}
}
另一种方法是询问而不是告诉其他参与者,在这种情况下,您拥有与要求总和的参与者相同数量的期货。 通过理解,您可以计算最终值,但是以上是ud通常处理这些情况的方式。 因此,如果上述参与者发送了一些数字串给不同的参与者以计算总和,然后报告总和,则您可以在求和请求中保留一些ID,以便上方的参与者知道他希望接收多少总和以及ID进行汇总,然后可以在收到最后一笔款项后将结果发送出去。
for {
a <- actor1 ? SumUp(valueList1)
b <- actor3 ? SumUp(valueList2)
} yield extractFromResponse(a) + extractFromResponse(b)
其中extractFromResponse是一些函数,用于解释接收到的消息并提取计算出的值。 在产生的将来,您可以使用.onComplete调用将汇总结果发送给父级。
答案 2 :(得分:0)
以下是Scala中的解决方案,我相信可以将其转换为Java而不会带来太多麻烦。鉴于您的要求(即使用一批童工来集体执行计算任务),我建议使用router。
这是一个由Master
演员组成的准系统摘要,该演员将Add
的工作委派给配置为Worker
路由的round-robin
子演员。在接收到来自子路径的工作结果后,var
角色中将计算结果的Master
保持可变,以进行增量更新。
import akka.actor.{Props, ActorSystem, Actor, ActorLogging}
import akka.routing.RoundRobinPool
case class CalcSum(l: List[Double])
case class Add(x: Double, y: Double)
case class Result(value: Double)
case object GetResult
class Worker extends Actor with ActorLogging {
def sum(x: Double, y: Double): Result = Result(x + y)
def receive = {
case Add(x, y) =>
sender ! sum(x, y)
case _ =>
log.error("Unknown work request!")
}
}
class Master(nrOfWorkers: Int) extends Actor with ActorLogging {
private var numbers: List[Double] = List.empty[Double]
private var result: Double = 0.0
private var nrOfWorkResults: Int = 0
val workerRouter = context.actorOf(
Props[Worker].withRouter(RoundRobinPool(nrOfWorkers)), name = "workerRouter"
)
def receive = {
case CalcSum(l: List[Double]) =>
numbers = l
result = 0.0
nrOfWorkResults = 0
l.foreach(x => workerRouter ! Add(result, x))
case Result(value) =>
result += value
nrOfWorkResults += 1
case GetResult =>
if (nrOfWorkResults < numbers.size - 1)
log.info("Calculation still in progress ... Please check again later.")
else
log.info(s"Result: $result")
}
}
object Master {
def props(nrOfWorkers: Int): Props = Props(new Master(nrOfWorkers))
}
请注意,这是一个非常基本的示例,例如可以通过context.become进行热交换功能进行完善,以最大限度地减少对可变var
的需求,等等。
使用4个worker
角色的路由器运行测试,以计算数值列表1到1,000,000的总和:
implicit val system = ActorSystem("system")
implicit val ec = system.dispatcher
val master = system.actorOf(Master.props(nrOfWorkers = 4), name = "master")
master ! CalcSum( List.iterate(1.0, 1000000)(_ + 1) )
master ! GetResult
// [INFO] [04/05/2019 14:20:44.747] [system-akka.actor.default-dispatcher-9]
// [akka://system/user/master] Result: 5.000005E11
由于1到N的总和等于N * (N + 1) / 2
,因此可以轻松地进行验证。