Я все время пытаюсь заставить это работать. Новичок в scala и для актеров, поэтому может непреднамеренно принимать плохие дизайнерские решения - пожалуйста, скажите мне, если так.
Установка такова:
У меня есть управляющий актер, который содержит несколько рабочих актеров. Каждый работник представляет расчет, который для данного входа будет выплевывать 1..n выходов. Контроллер должен отключить каждого работника, собрать возвращенные результаты, затем продолжить и сделать еще кучу вещей, как только это будет завершено. Вот как я подошел к этому, используя receive
в актере контроллера:
class WorkerActor extends Actor {
def act() {
loop {
react {
case DoJob =>
for (1 to n) sender ! Result
sender ! Done
}
}
}
}
Рабочий актер достаточно прост - он выдает результаты до тех пор, пока не выполнит его, когда отправляет обратно сообщение Done
.
class ControllerActor(val workers: List[WorkerActor]) extends Actor {
def act() {
workers.foreach(w => w ! DoJob)
receiveResults(workers.size)
//do a bunch of other stuff
}
def receiveResults(count: Int) {
if (count == 0) return
receive {
case Result =>
// do something with this result (that updates own mutable state)
receiveResults(count)
case Done
receiveResults(count - 1)
}
}
}
Актер-контролер запускает каждого из рабочих, затем рекурсивно принимает вызовы до тех пор, пока не получит сообщение Done
для каждого из рабочих.
Это работает, но мне нужно создать множество актеров контроллера, поэтому receive
слишком тяжелый - мне нужно заменить его на react
.
Однако, когда я использую react
, закулисное исключение срабатывает после обработки окончательного сообщения Done
, и метод act
субъекта контроллера замыкается накоротко, поэтому ни один из "//do a bunch of other stuff
", которое приходит после того, как происходит.
Я могу заставить что-то произойти после последнего Done
сообщения, используя andThen { }
- но мне действительно нужно выполнить несколько наборов вычислений таким образом, чтобы в итоге получилась смешно вложенная структура andThen { andThen { andThen } }
с.
Я также хочу скрыть эту сложность в методе, который затем будет перемещен в отдельную черту, так что актер-контроллер с несколькими списками рабочих актеров может просто выглядеть примерно так:
class ControllerActor extends Actor with CalculatingTrait {
//CalculatingTrait has performCalculations method
val listOne: List[WorkerActor]
val ListTwo: List[WorkerActor]
def act {
performCalculations(listOne)
performCalculations(listTwo)
}
}
Так есть ли способ остановить короткое замыкание метода act
в методе executeCalculations? Есть ли лучший дизайнерский подход, который я мог бы использовать?