对比起我们习惯的行令式(imperative)编程模式,Actor编程模式更接近现实中的应用场景和功能测试模式。这是因为Actor是靠消息来驱动的,每种消息代表一项功能的运算指令
由于每个Actor的运算都在自己独立的线程里进行,所以我们不必担心Actor函数在运行中的交叉调用问题。Akka程序本就是一种原生的多线程程序,每个Actor都在一个自己的线程内独立运算它的receive函数
关于actor自有线程的实现?
在Akka编程里我们可以把每段可能产生异常的代码放到一个独立的Actor中去运算
父级Actor对发生异常的子级Actor有以下几种处理方式:
1、恢复运算(Resume):不必理会异常,保留当前状态,跳过当前异常消息,照常继续处理其它消息
2、重新启动(Restart):清除当前状态,保留邮箱及内容,终止当前Actor,再重新构建一个新的Actor实例,沿用原来的消息地址ActorRef继续工作
3、彻底终止(Stop):销毁当前Actor及ActorRef邮箱,把所有消息导向DeadLetter队列。
4、向上提交(Esculate):如果父级无法处理子级异常,则这种情况也视为父级出现的异常。按照规定,父级会将自己和子级Actor运算暂停挂起并把子级Actor实际产生的异常当作自己发生的异常提交给上一层父级处理(也就是说异常信息的发送者sender变成了父级Actor)
Akka处理异常的方式简单直接:如果发生异常就先暂停挂起然后交给直属父级Actor去处理。这就把异常封闭在这个Actor的监管链条里。Akka系统的监管链条实际代表一个功能的分散封闭运算,所以一个监管链条里发生的异常不会影响其它监管链条。换句话说就是Actor发生异常是封闭在它所属的功能内部的,一个功能发生异常不会影响其它功能。
Akka提供了OneForOneStrategy和AllForOneStrategy两种对待异常Actor的策略配置
OneForOneStrategy:只针对发生异常的Actor施用策略
AllForOneStrategy:虽然一个直属子级Actor发生了异常,监管父级Actor把它当作所有下属子级同时发生了相同异常,对所有子级Actor施用策略
生命周期
preStart
preStop
Akka提供了一种逐步延时重启策略(BackoffSupervisor)
1 | val childProps = Props(classOf[EchoActor]) |
Akka提供了context.watch和context.unwatch来设置通过ActorRef对任何Actor的终止状态监视,无须父子级别关系要求。但是还是要求当前为actor?
生命周期监控函数中只有postStop被调用过,preRestart和postRestart都没引用。如果这样的话BackoffSupervisor就是一锤子买卖,是正真的let it crash模式体现了。