10.5 actor
方法
在上面的例子里,我们控制了actor何时启动。如果对显式启动actor并不真的那么关注,那么可以使用actor()
方法。在actor间传递数据,可以用!()
和receive()
方法。下面从一个使用actor()
方法的例子开始,然后重构,使其并发。
这个方法(isPrime()
)告诉我们给定的数是不是素数。为了达到说明的目的,我在方法里加了一些打印语句:
ConcurrentProgramming/PrimeTeller.scala
import scala.actors._
import Actor._
def isPrime(number: Int) = {
println("Going to find if " + number + " is prime")
var result = true
if (number == 2 || number == 3) result = true
for (i <- 2 to Math.sqrt(number.toDouble).floor.toInt; if result) {
if (number % i == 0) result = false
}
println("done finding if " + number + " is prime")
result
}
调用上面这段代码的话,接收到应答之前,就会阻塞在那里。如下所示,这里把调用这个方法的职责委托给一个actor。这个actor会确定一个数是否是素数,然后,用一个异步响应发回给调用者。
ConcurrentProgramming/PrimeTeller.scala
Line 1 val primeTeller = actor {
2 var continue = true
3
4 while (continue) {
5 receive {
6 case (caller : Actor, number: Int) => caller ! (number,
isPrime(number))
7 case "quit" => continue = false
8 }
9 }
10 }
primeTeller
是一个引用,它指向了用actor()
方法创建的一个匿名actor。它会不断循环,直到接收到“quit”消息。除了退出消息,它还能接收一个包含caller
和number
的元组。收到这个消息时,它会判断给定的数是否是素数,然后,给caller
发回一个消息。
下面让这个actor判断任意三个数(2, 131, 132)
是否是素数:
ConcurrentProgramming/PrimeTeller.scala
primeTeller ! (self, 2)
primeTeller ! (self, 131)
primeTeller ! (self, 132)
for (i <-1 to 3){
receive {
case (number, result) => println(number + " is prime? " + result)
}
}
primeTeller ! "quit"
上面的代码处理了接收到的每个数字;从下面的输出上,可以看到这一点。在actor忙于判断一个数是否是素数时,如果又接收到多个请求,它们就会进入队列。因此,即便是将执行委托给了actor,它依然是顺序的。
Going to find if 2 is prime
done finding if 2 is prime
2 is prime? true
Going to find if 131 is prime
done finding if 131 is prime
Going to find if 132 is prime
131 is prime? true
done finding if 132 is prime
132 is prime? false
别害怕,让这个例子并行相当容易,这样,它就可以同时处理多个请求了。在primeTeller
actor的第6行,不要去调用isPrime()
,而是把这个职责委托给另一个actor,让它给调用者回复应答:
//case (caller : Actor, number: Int) => caller ! (number, isPrime(number))
case (caller : Actor, number: Int) => actor { caller ! (number,
isPrime(number)) }
再次运行上面的代码,我们会看到,多个请求并发地执行了,如下所示:
Going to find if 131 is prime
Going to find if 2 is prime
Going to find if 132 is prime
done finding if 2 is prime
done finding if 131 is prime
2 is prime? true
131 is prime? true
done finding if 132 is prime
132 is prime? false
以线程安全的方式编写并发代码毫不费力。记住,这里成功的关键在于不变对象。绝对不要在线程间共享公共状态——我是指actor。
上面的输出还可以从另外一个角度观察——与actor交互的顺序是没有任何保证的。actor接收到消息就可以进行处理,只要准备好就可以应答。actor对消息的接收和处理没有预先强加的顺序。