张贵宾
2011.10.31
在这一章中我们看看如何在并行的基于actor的程序中处理错误。Actors与顺序的Scala代码相比,提供了几种处理异常的额外方法。特别的,我们将展示actor如何处理他们抛出的但不能被其他actor处理的异常。更普遍的,我们将寻找一种actor能够监控其他actor的方式,通过这种方式能够检测到其他的actor是正常的终止了,还是抛出异常后非正常退出了。最后,我们介绍了一些概念和技术,这些概念和技术能够简单的终止基于actor程序的管理。
最简单看护那些由于异常抛出而默默终止的actor的方法就是提供一个全局的异常处理器,任何一个actor执行体内有异常抛出时都会调用这个异常处理器。我们可以继承Actor(或者Reactor)并重写它的exceptionHandler成员函数即可。(exceptionHandler成员函数定义在Reactor中,而Actor中的继承关系是:ReplyActor继承自Reactor,Actor继承自Reactor)在Reactor中,exceptionHandler成员函数的签名是:def exceptionHandler: PartialFunction[Exception, Unit]
object A extends Actor { def act() { react { case 'hello => throw new Exception("Error!") } } override def exceptionHandler = { case e: Exception => println(e.getMessage) } }
上面的代码展示了如何复写exceptionHandler方法之后让它返回一个客户化的偏函数。下面让我们使用Scala的解释shell与actor A交互看看效果:
scala> import scala.actors._ import scala.actors._ scala> object A extends Actor { | def act() { | react { | case 'hello => | throw new Exception("Error!") | } | } | | override def exceptionHandler = { | case e: Exception => | println(e.getMessage) | } | } defined module A scala> A.start res0: scala.actors.Actor = A$@65dfb0b5 scala> A ! 'hello scala> Error!
使用exceptionHandler这种形式的异常处理与诸如loop这样的控制流组合器一同工作的非常好,组合器能被用于在处理了异常之后,恢复正常执行的actor。比如我们把actor A中act方法修改成如下形式:
object A extends Actor { def act() { var lastMsg: Option[Symbol] = None loopWhile(lastMsg.isEmpty || lastMsg.get != 'stop) { react { case 'hello => throw new Exception("Error!") case any: Symbol => println("your message: " + any) lastMsg = Some(any) } } } override def exceptionHandler = { case e: Exception => println(e.getMessage) } }
下面我们在Scala的命令行中测试一下:
scala> import scala.actors._ import scala.actors._ scala> object A extends Actor { | def act() { | var lastMsg: Option[Symbol] = None | loopWhile(lastMsg.isEmpty || lastMsg.get != 'stop) { | react { | case 'hello => | throw new Exception("Error!") | case any: Symbol => | println("your message: " + any) | lastMsg = Some(any) | } | } | } | | override def exceptionHandler = { | case e: Exception => | println(e.getMessage) | } | } defined module A scala> A.start res0: scala.actors.Actor = A$@52620402 scala> A ! 'hello scala> Error! scala> A.getState res2: scala.actors.Actor.State.Value = Suspended scala> A ! 'hi your message: 'hi scala> A ! 'stop your message: 'stop scala> A.getState res5: scala.actors.Actor.State.Value = Terminated