我需要将一系列远程调用切成块。我想过要用演员。
我想到了这样的事情:
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是一种好习惯吗?出于某种原因,我没有看到任何人这样做。
答案 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。但你所做的事情并没有错。