Actors in Scala(Scala中的Actor)(预打印版) 第六章 Exception Handling, Actor Termination and Shutdown(A)

翻译 2011年10月31日 16:13:55
Actors in Scala(Scala中的Actor)(预打印版) 第六章 Exception Handling, Actor Termination and Shutdown(A)

张贵宾

guibin.beijing@gmail.com

2011.10.31

在这一章中我们看看如何在并行的基于actor的程序中处理错误。Actors与顺序的Scala代码相比,提供了几种处理异常的额外方法。特别的,我们将展示actor如何处理他们抛出的但不能被其他actor处理的异常。更普遍的,我们将寻找一种actor能够监控其他actor的方式,通过这种方式能够检测到其他的actor是正常的终止了,还是抛出异常后非正常退出了。最后,我们介绍了一些概念和技术,这些概念和技术能够简单的终止基于actor程序的管理。


6.1 Simple exception handling(简单异常处理)

当一个actor在其执行体内抛出了未被处理的异常后,此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是一个没有参数的,且返回值是偏函数的方法,在这里它能够处理java.lang.Exception类型的异常。任何时候从actor的函数体中抛出一个异常通常都会导致actor终止运行,当抛出异常时,运行时系统会检测actor的exceptionHandler方法能否匹配到抛出的异常类型,如果能匹配到,exceptionHandler偏函数就被应用到这个异常上,调用完exceptionHandler之后,actor会正常的终止运行。


上面的代码展示了如何复写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方法运行了,因此打印出了抛出异常上附带的消息字符串:"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)
  }
}

react方法的调用现在被包裹在了loopWhile中,loopWhile会测试最后收到的消息是否等于 'stop ,如果等于则终止actor。现在,如果actor收到一条 'hello 消息,它将抛出异常,这个异常将会被exceptionHandler处理,处理完毕异常之后actor不会终止运行,而是通过继续执行下一个loop迭代而恢复运行。这就意味着在处理完毕了异常之后,actor能够继续工作,继续准备接收更多的消息。


下面我们在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


注意在发送了 'hello 之后,actor A最终暂停,等待下一条消息的到来。getState方法能够用来查询actor的执行状态,它会返回Actor.State类型的枚举类型,这些类型都定义在scala.actors.Actor对象中。Suspended状态表示actor已经调用了react方法,目前正在等待合适的(能匹配得上的)消息。因此,我们能够继续发送 'hi 消息和actor交互。在actor收到了 'stop 消息之后,它的loopWhile循环终止,actor也正常的终止了,因此最终actor的状态是Terminated。


Scala Actor并发编程

Scala 并发编程介绍,Scala Actor实例及匿名Actor创建方法。最后介绍Scala Actor和case class 以及接收回传消息的方法。...
  • yyywyr
  • yyywyr
  • 2016年01月05日 22:12
  • 2640

一个超简单的akka actor例子

一个超简单的akka actor例子 抛开复杂的业务逻辑,让我们从一个超级简单的例子学习Akka Actor的用法。 Scala cookbook的作者Alvin Alexander在他的网...
  • sinat_27169251
  • sinat_27169251
  • 2016年07月29日 11:32
  • 1896

Scala中的Actor入门笔记

核心内容: 1、Java中的并发编程思想与Scala中的并发编程思想 2、Scala中Actor的两种创建方式、Actor中的receive偏函数在进行模式匹配时与传统模式匹配的区别、receiv...
  • a2011480169
  • a2011480169
  • 2016年11月07日 10:33
  • 3073

Scala学习笔记11 - Actor和并发

===Actor和并发       与java的基于共享数据和锁的线程模型不同,scala的actor包则提供了另外一种不共享任何数据、依赖消息传递的模型。设计并发软件时,actor是首选的工具,因为...
  • guohecang
  • guohecang
  • 2016年08月04日 11:57
  • 997

Scala基于Akka的Remote Actor实现的简单RPC

spark 1.3中的通信是基于Akka实现的,Actor之间的交互都是通过消息,并且所有动作都是异步的。 本文基于spark 1.3通信核心原理实现一个简单的基于akka的rpc框架。 服务端:...
  • xiaomage167
  • xiaomage167
  • 2017年03月13日 15:49
  • 552

scala之Akka的Actor模型(下)

原文地址:http://my.oschina.net/jingxing05/blog/287462
  • shenlanzifa
  • shenlanzifa
  • 2014年09月26日 10:22
  • 1648

scala之Akka的Actor模型(上)

原文地址:http://my.oschina.net/jingxing05/blog/287213 明确并行和并发 看两张图 并行parallelism 并发c...
  • shenlanzifa
  • shenlanzifa
  • 2014年09月26日 10:24
  • 1205

Akka并发编程——第六节:Actor模型(五)

本将主要内容: 1. !消息发送,Fire-and-Forget消息模型 2. ?消息发送,Send-And-Receive-Future消息模型Akka提供了两种消息模型:fire-and-fo...
  • lovehuangjiaju
  • lovehuangjiaju
  • 2016年06月03日 23:17
  • 15415

Scala:简单使用Actor的消息发送与接收求和

原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://haolloyin.blog.51cto.com/1177454/391310 ...
  • xygg0801
  • xygg0801
  • 2017年02月22日 17:40
  • 612

Akka学习笔记:Actor消息处理-请求和响应(2)

接《Akka学习笔记:Actor消息处理-请求和响应(1)》 文章目录 [hide] 0.1 二、StudentActor对InitSignal消息作出反应,并且发送了Quot...
  • xiaolang85
  • xiaolang85
  • 2016年06月15日 17:50
  • 1384
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Actors in Scala(Scala中的Actor)(预打印版) 第六章 Exception Handling, Actor Termination and Shutdown(A)
举报原因:
原因补充:

(最多只允许输入30个字)