一、前言
考虑一个发送消息给另一个actor的actor。如果每个actor都在单独的线程中运行,我们很容易实现控制流转。作为消息发送方的actor将消息发到邮箱中,然后它的线程继续执行。而每当有条目被放入邮箱时,作为消息接收方的actor的线程就会被唤醒。
在有些程序所包含的actor是如此之多,以至于要为每个actor创建独立的线程开销很大。所以实际需求中,我们肯定不能这样做,我们必须使得一个actor可以多次被使用,而不是频繁地创建,销毁。
二、react控制流原理以及while的共享失效性
以下采用快学scala教材的一个例子:
2-1 例子:react的控制流原理
/**
* 这里的Withdraw,Confirm分别是两个不同类型的函数
*/
react{//函数f1
case Withdraw(amount) =>
react {//函数f2
case Confirm() =>
println("Confirming "+amount)
}
}
它的控制流过程是这样的:第一个react的调用讲将f1与actor的邮箱关联起来,然后退出。当Withdraw消息抵达时,f1被调用。函数f1也调用了react。这次调用把f2与actor的邮箱关联起来;然后退出。当Confirm消息抵达时,f2被调用。
由于react会退出,所以你不能简单地把它放进whlile循环中
2-2例子:while的共享失效性
<pre name="code" class="java"><pre name="code" class="java"> while(true){
react{//函数1
case Withdraw(amount) =>
println("Confirming "+amount)
}
print("haha")//这个句子在react被调用并把f1函数送到邮箱时,立马执行。这意味着print(“haha”)与react执行体不在同一个线程内串行执行
}
这个例子中,react执行体会被送到邮箱中,可以理解为它的执行是在另一个线程里。这也意味着需要重复利用的actor在print("haha")后就自动挂掉,无法重复利用。
</pre><pre name="code" class="java">def act(){
react{//函数1
case Withdraw(amount) =>
println("Confirming "+amount) <pre name="code" class="java"> act()
} }
这样做就意味着用一个无穷递归来替换无穷循环
</pre>2-4例子:scala中loop,loopwhile()可以实现这种“控制流转组合子”</p><p><pre name="code" class="java">def act(){
loop{
react{//函数1
case Withdraw(amount) =>
println("Confirming "+amount)
}
}
}
三、react 实例
以下使用 无穷递归的方式来共享Actor
3-1经典例子:
<pre name="code" class="java">import java.net.InetAddress
import java.net.UnknownHostException
import actors._, Actor._
import scala.actors.Actor
/**
* scala Actor构建在java的线程基础之上的,
* 为了避免频繁的线程创建、销毁和切换等,scala中提供了react方法
* 方法执行完毕后,仍然被保留 (这里是指线程)
*/
object NameResolver extends Actor{
def act(){
react{
/**
* 该例中,以下所有内容都会与邮箱关联起来,让邮箱去执行,然后当前react退出,
* 所以说当前react是没有任何办法返回到当前act()方法当中
* 下面会调用act来构造一个无限递归
*/
case Net(name,actor) =>
actor!getIpAddress(name) //
//再次调用act方法,从本身邮箱中读取消息 ,如果消息为空,则等待
//这里act相当在无限递归自身方法
act
case "EXIT" =>
println("Name resolver exiting.")
//匹配邮箱中的单个信息,本例中会匹配邮箱中的IP地址信息
case msg =>
println("Unhandled message: " + msg)
act
}
}
def getIpAddress(name:String):Option[InetAddress] ={
try{
println(InetAddress.getByName(name))
Some(InetAddress.getByName(name))
} catch {
case _: UnknownHostException => None
}
}
}
case class Net(name:String,actor:Actor)
object ActorWithReAct extends App {
//启动Actor
NameResolver.start()
//发消息
NameResolver!Net("www.baidu.com",self)
//接收消息
println(self.receive{case msg => msg})
}
3-2结果
www.baidu.com/14.215.177.38
Some(www.baidu.com/14.215.177.38)