10.4 Actor
类
在上面的代码里,用到了Actor
单例对象的actor()
方法。大多数情况下,它就够用了。不过,如果想在actor启动时进行显式控制,希望在actor里存入更多信息,可以创建一个对象,混入Actor
trait。这是对的——Scala的Actor
只是个trait,可以在任何喜欢的地方混入它。下面是个例子:
ConcurrentProgramming/AnsweringService.scala
import scala.actors._
import Actor._
class AnsweringService(val folks: String*) extends Actor {
def act() {
while(true){
receive {
case (caller : Actor, name : String, msg : String) =>
caller ! (
if(folks.contains(name))
String.format("Hey it's %s got message %s", name, msg)
else
String.format("Hey there's no one with the name %s here", name)
)
case "ping" => println("ping!")
case "quit" => println("exiting actor")
exit
}
}
}
}
这里创建了一个AnsweringService
类,混入了trait Actor
;记住,如果没有继承任何类,就可以用关键字extends
混入trait(参见7.1节)。AnsweringService
接收一个数组作为构造函数参数,数组的元素是系统可识别的名字。在类里实现必需的act()
方法(这个方法在Actor
trait里是抽象的)。在这个方法里,处理了三种类型的消息:一个元组和两个字面量,“ping”和“quit”:
ConcurrentProgramming/AnsweringService.scala
val answeringService1 = new AnsweringService("Sara", "Kara", "John")
answeringService1 ! (self, "Sara", "In town")
answeringService1 ! (self, "Kara", "Go shopping?")
answeringService1.start()
answeringService1 ! (self, "John", "Bug fixed?")
answeringService1 ! (self, "Bill", "What's up")
for(i <- 1 to 4) { receive { case msg => println(msg) } }
answeringService1 ! "ping"
answeringService1 ! "quit"
answeringService1 ! "ping"
Thread.sleep(2000)
println("The last ping was not processed")
上面代码的输出如下:
Hey it's Sara got message In town
Hey it's Kara got message Go shopping?
Hey it's John got message Bug fixed?
Hey there's no one with the name Bill here
ping!
exiting actor
The last ping was not processed
开始,我们给actor发送了一些元组消息。这些消息不会立即得到处理,因为actor还没有启动。它们会进入队列,等待后续处理。然后调用start()
方法,再发送一些消息。只要调用了start()
方法,就会有一个单独的线程调用actor的act()
方法。这时,曾经发出去的所有消息都开始进行处理。然后,我们循环接收对发出的四条消息的应答。
调用exit()
方法可以停止actor。不过,这个方法只是抛出异常,试图终止当前线程的执行,所以,在act()
方法里调用挺不错。这个方法的一个变体还可以用退出原因作为参数,如果确实在意要给出一个原因的话就用它吧。在上面的代码里,收到“quit”消息时,调用了exit()
方法终止这个actor的执行。发送“quit”消息之前发送的“ping”消息得到了处理,之后的就没有处理。从输出里可以看到这一点。调用exit()
之后发送的任何消息都直接进入队列。如果愿意的话,也可以调用start()
方法重启actor。它会先处理队列里的消息,然后处理接收到的消息。