Ниже приведено решение в 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
, следовательно, легко проверяется.