Как сделать так, чтобы акторы scala сообщали о завершении задачи?

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

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

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{ ... }

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

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

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


person Pico    schedule 30.03.2012    source источник
comment
Как я говорю всем, кто задает вопросы об актерах Scala, обратите внимание на Akka. Он имеет очень высокую концентрацию awesome.   -  person leedm777    schedule 30.03.2012


Ответы (2)


Вы в полном порядке; необработанные сообщения в акторе будут просто попадать в почтовый ящик и обрабатываться, когда актор будет к ним готов. Однако, что касается акторов, отвечающих своим вызывающим абонентам, вам обычно не нужно передавать ссылку на 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()) и каким-то образом использовать его результат (например, распечатать его).

person Destin    schedule 30.03.2012

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

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

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

person leedm777    schedule 30.03.2012