如何让scala actor报告任务完成?

时间:2012-03-30 02:20:20

标签: scala actor

我需要将一系列远程调用切成块。我想过要用演员。

我想到了这样的事情:

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实例可能已经完成执行。如果他们向尚未处于消息接收状态的actor发送消息会发生什么?消息是排队还是被丢弃?

最重要的是:如何创建能够通知创建它们的actor的子actor,即使它们返回的速度非常快?

还相关:将当前actor实例(this)传递给其他actor是一种好习惯吗?出于某种原因,我没有看到任何人这样做。

2 个答案:

答案 0 :(得分:2)

你很好;演员中的未处理消息将直接进入邮箱,并在演员准备好时进行处理。但是,对于回复其调用者的actor,您通常不需要传递对this的引用,因为actor可以使用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 :(得分:1)

只要演员已经开始,发送给它的消息就会排队等待下一次接收/反应。

通过构造函数传递actor也没问题,但是你应该将它们作为Actor而不是派生类型传递,以消除直接访问actor状态的诱惑。

您通常不会看到这一点,因为通常会在消息中传递actor。但你所做的事情并没有错。