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

本文主要是介绍Actors in Scala(Scala中的Actor)(预打印版) 第六章 Exception Handling, Actor Termination and Shutdown(A),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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 Ascala> A.start
res0: scala.actors.Actor = A$@65dfb0b5scala> A ! 'helloscala> Error!

正像我们所期望的,exceptionHandler方法运行了,因此打印出了抛出异常上附带的消息字符串:"Error!"


使用exceptionHandler这种形式的异常处理与诸如loop这样的控制流组合器一同工作的非常好,组合器能被用于在处理了异常之后,恢复正常执行的actor。比如我们把actor A中act方法修改成如下形式:

object A extends Actor {def act() {var lastMsg: Option[Symbol] = NoneloopWhile(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 Ascala> A.start
res0: scala.actors.Actor = A$@52620402scala> A ! 'helloscala> Error!scala> A.getState
res2: scala.actors.Actor.State.Value = Suspendedscala> A ! 'hi
your message: 'hiscala> A ! 'stop
your message: 'stopscala> 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。


这篇关于Actors in Scala(Scala中的Actor)(预打印版) 第六章 Exception Handling, Actor Termination and Shutdown(A)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/688786

相关文章

第六章习题11.输出以下图形

🌏个人博客:尹蓝锐的博客 希望文章能够给到初学的你一些启发~ 如果觉得文章对你有帮助的话,点赞 + 关注+ 收藏支持一下笔者吧~ 1、题目要求: 输出以下图形

多数据源的事务处理总是打印很多无用的log日志

之前做了一个项目,需要用到多数据源以及事务处理,在使用事务处理,服务器总是打印很多关于事务处理的log日志(com.atomikos.logging.Slf4jLogger),但是我们根本不会用到这些log日志,反而使得查询一些有用的log日志变得困难。那要如何屏蔽这些log日志呢? 之前的项目是提高项目打印log日志的级别,后来觉得这样治标不治本。 现在有一个更好的方法: 我使用的是log

fastreport打印trichedit分页问题的解决

用fastreport来打印richedit里面的内容。刚开始放一个frxrichview组件到报表上,然后在 var str: TMemoryStream; begin    begin      str:= TMemoryStream.Create;      CurrRichRecord.richedit.Lines.SaveToStream(str);      str.Posit

模具要不要建设3D打印中心

随着3D打印技术的日益成熟与广泛应用,模具企业迎来了自建3D打印中心的热潮。这一举措不仅为企业带来了前所未有的发展机遇,同时也伴随着一系列需要克服的挑战,如何看待企业引进增材制造,小编为您全面分析。 机遇篇: 加速产品创新:3D打印技术如同一把钥匙,为模具企业解锁了快速迭代产品设计的可能。企业能够迅速将创意转化为实体模型,缩短产品从设计到市场的周期,抢占市场先机。 强化定制化服务:面

Java项目中,配置打印 JDBC 日志的几种方法

在 IDEA 项目中,如果你想打印 JDBC 日志,可以通过配置日志框架(如 Logback 或 Log4j)来实现。Spring Boot 使用的默认日志框架是 Logback,你可以通过在 application.yml 文件中配置日志级别来打印 JDBC 日志。 方法 1: 使用 application.yml 配置 JDBC 日志 logging:level:# 显示 SQL 语句co

【虚拟机/服务器】XAMPP错误: Apache shutdown unexpectedly解决办法

XAMPP安装好之后启动,但有些用户在启动apache的时候会出现: 11:41:38 [Apache] Status change detected: running11:41:38 [Apache] Status change detected: stopped11:41:38 [Apache] Error: Apache shutdown unexpectedly.11:41:38

Go语言设计与实现 学习笔记 第六章 并发编程(3)

系统调用 系统调用对于Go语言调度器的调度也有比较大的影响,为了处理这些特殊的系统调用,我们甚至专门在Goroutine中加入了_Gsyscall这一状态,Go语言通过Syscall和Rawsyscall等使用汇编语言编写的方法封装了操作系统提供的所有系统调用,其中Syscall在Linux 386上的实现如下: // 定义名为.Syscall的函数,该函数不允许栈分割,栈帧大小为0,有28字

一个C++程序运行,从点击运行到控制台打印文本,电脑硬件的资源是如何调动的

当点击运行一个 C++ 程序并看到控制台输出文本时,计算机硬件和操作系统之间协同工作,完成了多个步骤。这些步骤涉及 CPU、内存、存储设备、操作系统和输入输出设备的共同作用。下面是一个详细的过程描述: 1. 程序加载 启动:当你点击运行一个可执行文件时,操作系统(通常是 Windows、Linux 或 macOS)的文件系统管理器识别请求,并启动加载程序。读取可执行文件:加载程序将可执行文件从

myEclipse失去焦点时报错Unhandled event loop exception的解决方案

一句话:百度杀毒惹的祸。。。。果断卸载后问题解决。

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFArra

这个错误说的是一个不可变数组负值给了一个可变的数组。有可能你前面定义的数组是一个可变数组,但是在你其他方法里面用他的时候,他就是一个不可变数组,因为在可变数组拿到别的地方用的时候,他会默认为不可变的,可能这只是一个类里面你只是简单的声明了他吧,并没有进行对他初始化,或者分配什么内存,所以他只是一个不可变的数组,当你在其他地方用他的时候,他就默认为不可变的数组,他可能因为你的没分配内存,而变回不可变