Как сделать так, чтобы актеры скалы сообщали о завершении задачи? - PullRequest
2 голосов
/ 30 марта 2012

Мне нужно разделить серию удаленных вызовов на куски. Я думал об использовании актеров.

Я думал о чем-то вроде этого:

class ControlActor() extends Actor{
  var counter = 1000
  def act{
     for (i <- 1 until 1000) { new RequestActor(this) start }
    while(true){
      receive{
        case "Stop" =>{counter = counter-1; if(counter==0){return}}
      }
    } 
  }
}

class RequestActor(parent:ControlActor) extends actor{ ... }

но здесь есть очевидная проблема: когда я попадаю в блок recieve, некоторые экземпляры RequestActor могут уже завершиться. Что произойдет, если они отправят сообщение субъекту, который еще не находится в состоянии получения сообщения? сообщение попадает в очередь или отбрасывается?

Самое важное: как создать дочерних актеров, способных уведомить создателя, даже если они возвращаются очень быстро?

Также связано: Является ли хорошей практикой передача текущего экземпляра актера (this) другим актерам? По какой-то причине я не видел, чтобы кто-нибудь делал это.

Ответы [ 2 ]

2 голосов
/ 30 марта 2012

Ты в порядке;необработанные сообщения в актере будут просто помещаться в почтовый ящик и обрабатываться, когда актер будет готов к ним.Однако, что касается актеров, отвечающих на своих абонентов, вам обычно не нужно передавать ссылку на this, потому что актеры могут напрямую общаться с вызывающим абонентом с помощью reply.Вот простой пример:

class MyActor(n: Int) extends Actor {
  def act() {
    loop {
      react {
        case m: Int => reply(n + m)  // Use `reply` to reply to caller
      }
    }
  }
}

// new MyActor(0), new MyActor(10), new MyActor(20), ...
val actors = (0 to 100 by 10) map (new MyActor(_).start())

// Message each actor with '5', expecting a response (that's what `!?` does)
val responses = actors map (_ !? 5)
responses foreach println

приводит к

5
15
25
35
45
55
65
75
85
95
105

Оператор !?, однако, будет блокировать основной поток, пока мы не получим ответ на его сообщение.В результате, actors map (_ !? 5) на самом деле не так уж и параллелен.Вместо этого вы можете использовать !! для генерации фьючерсов (которые вы тем временем можете позволить вычислить и отложить оценку до готовности).Итак ... изменение этих двух последних строк на

val futures = actors map (_ !! 5)
futures foreach (future => println(future()))

сообщит первому актеру «5», давая мне будущее, за которое он должен удержаться, а затем сообщит второму актеру «5»', давая мне будущее, которое нужно удержать в то же время и т. д., и когда мы будем готовы, мы можем оценить будущее (future()) и каким-то образом использовать его результат (например, распечатать его).

1 голос
/ 30 марта 2012

Пока актер запущен, отправленные ему сообщения будут помещаться в очередь для следующего вызова приема / реагирования.

Передача актеров через конструктор тоже подойдет, но вместо этого вы должны передать их как актера.производного типа, чтобы удалить соблазн прямого доступа к состоянию актера.

Обычно вы этого не видите, потому что обычно акторы передаются в сообщениях.Но нет ничего плохого в том, что вы делаете.

...