10.6 receive
和receiveWithin
方法
receive()
接收一个函数值/闭包,返回一个处理消息的应答。下面是个从receive()
方法接收结果的例子:
ConcurrentProgramming/Receive.scala
import scala.actors.Actor._
val caller = self
val accumulator = actor {
var sum = 0
var continue = true
while (continue) {
sum += receive {
case number : Int => number
case "quit" =>
continue = false
0
}
}
caller ! sum
}
accumulator ! 1
accumulator ! 7
accumulator ! 8
accumulator ! "quit"
receive { case result => println("Total is " + result) }
accumulator
接收数字,对传给它的数字求和。完成之后,它会发回一个消息,带有求和的结果。上面的代码输出如下:
Total is 16
上面的代码告诉我们,即便receive()
有着特殊的意义,它也只不过是另一个方法。不过,调用receive()
会造成程序阻塞,直到实际接收到应答为止。如果预期的actor应答一直没有发过来就麻烦了。这会让我们一直等下去——一个活性失败(liveness failure)——这会让我们在同事间不得人心的。用receiveWithin()
方法修正这一点,它会接收一个timeout
参数,如下:
ConcurrentProgramming/ReceiveWithin.scala
import scala.actors._
import scala.actors.Actor._
val caller = self
val accumulator = actor {
var sum = 0
var continue = true
while (continue) {
sum += receiveWithin(1000) {
case number : Int => number
case TIMEOUT =>
println("Timed out! Will return result now")
continue = false
0
}
}
caller ! sum
}
accumulator ! 1
accumulator ! 7
accumulator ! 8
receiveWithin(10000) { case result => println("Total is " + result) }
在给定的超时期限内,如果什么都没收到,receiveWithin()
方法会收到一个TIMEOUT
消息。如果不对其进行模式匹配,就会抛出异常。在上面的代码里,接收到TIMEOUT
消息当作了完成值累加的信号。输出如下:
Timed out! Will return result now
Total is 16
我们应该倾向于使用receiveWithin()
方法而非receive()
方法,避免产生活性等待的问题。
呃,关于receive()
和receiveWithin()
,还有最后一件事要讲——它们相当勤奋,不会浪费时间在它们不关心的消息上。因为这些方法把函数值当作偏应用函数,调用代码块之前,会检查它是否处理消息。所以,如果接收到一个非预期消息,就会悄悄地忽略它。当然,如果想把忽略的消息显示出来,可以提供一个case _ => …
语句。下面这个例子展示了忽略的无效消息:
ConcurrentProgramming/MessageIgnore.scala
import scala.actors._
import Actor._
val expectStringOrInteger = actor {
for(i <-1 to 4){
receiveWithin(1000) {
case str : String => println("You said " + str)
case num : Int => println("You gave " + num)
case TIMEOUT => println("Timed out!")
}
}
}
expectStringOrInteger ! "only constant is change"
expectStringOrInteger ! 1024
expectStringOrInteger ! 22.22
expectStringOrInteger ! (self, 1024)
receiveWithin(3000) { case _ =>}
在代码的最后,放了一个receiveWithin()
的调用。因为主线程退出时,程序就退出了,这个语句会保证程序还活动着,给actor一个应答的机会。从输出中可以看出,actor处理了前两个发送给它的消息,忽略了后两个,因为它们没有匹配上预期的消息模式。程序最终会超时,因为没有再接收到任何可以匹配的消息。
You said only constant is change
You gave 1024
Timed out!
Timed out!