我需要将一系列远程调用分割成块。我想过用演员。
我想到了这样的东西:
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
)传递给其他参与者是否是一种好的做法?由于某种原因,我没有看到任何人这样做。
你很好;actor中未处理的消息将直接进入邮箱,并在actor准备就绪时进行处理。但是,对于参与者回复其呼叫者,通常不需要传递对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()
)并以某种方式使用其结果(如打印出来)。
只要参与者已经启动,发送给它的消息就会排队等待下一个接收/反应调用。
通过构造函数传递Actor也是可以的,但应该将它们作为Actor而不是派生类型传递,以消除直接访问Actor状态的诱惑。
你通常不会看到这种情况,因为通常演员都是通过消息传递的。但是你所做的并没有错。