Как вернуть итоговые результаты двух дочерних акторов родителю и распечатать их - PullRequest
0 голосов
/ 05 апреля 2019

Я пытаюсь выяснить, как использовать несколько результатов, полученных родителем, и отправить их родителю.

Я достаточно хорошо разбираюсь в основах akka и знаю, какпередать сообщение и получить один ответ.Я теряюсь, когда мне нужно объединить два ответа в один результат (и затем передать этот результат).

Например: я хочу одновременно добавить сумму 1,2,3,4.Поэтому я отправляю сообщение, содержащее 1 и 2, ребенку и 3 и 4 другому ребенку.Они складывают свои соответствующие номера и отправляют ответ родителю, который в идеале суммирует 2 результата.

Ответы [ 3 ]

0 голосов
/ 05 апреля 2019

Вы можете сохранить параметр учета в родительском акторе, поэтому в коде 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
  }
}

Другой способ - попросить, а не сказать другим актерам, и в этом случае у вас будет такое же количество фьючерсов, что и у актеров, которых просят подвести итоги. Затем вы можете вычислить окончательное значение, но вышеизложенное показывает, как обычно обрабатывают эти случаи. Таким образом, в случае, если вышеуказанный субъект отправляет несколько групп чисел различным субъектам для вычисления сумм, а затем сообщает суммы, вы либо сохраняете некоторый идентификатор в запросах суммирования, чтобы вышеуказанный субъект знал, сколько сумм он ожидает получить, и идентификатор для суммировать и затем, получив последнюю сумму, отправить результат).

for {
 a <- actor1 ? SumUp(valueList1)
 b <- actor3 ? SumUp(valueList2)
} yield extractFromResponse(a) + extractFromResponse(b)

где extractFromResponse - это некоторая функция, которая интерпретирует полученное сообщение и извлекает вычисленное значение. В этом будущем вы будете использовать вызов .onComplete, чтобы отправить итоговый результат родителю.

0 голосов
/ 06 апреля 2019

Ниже приведено решение в 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 s и т. Д.

Тестовый запуск с маршрутизатором из 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, следовательно, легко проверяется.

0 голосов
/ 05 апреля 2019

Предполагая, что akka и java немного похожи, вы можете сделать

firstMethod(arguments) + secondMethod(arguments), поскольку вы пытаетесь добавить свои результаты. (дано из возвращаемых значений)

...