akka设计模式系列(Actor模型)
谈到Akka就必须介绍Actor并发模型,而谈到Actor就必须看一篇叫做《A Universal Modular Actor Formalism for Artificial Intelligence 》的论文,它最早发表于1973年,提出了一种并发计算的理论模型,Actor就源于该模型。
在Actor模型中,actor是一个并发原语,简单的说,一个actor就是一个工人,与进程或线程一样都能够工作或处理任务。其实这还有点不好理解,我们可以把它想象成面向对象编程语言中的一个对象实例。在OOP中一个对象可以访问或修改另一个对象的属性,也可以直接调用另一个对象的方法。例如下图,person1给person2发送了一个消息,直接调用方法就行了。深入底层执行逻辑的话,结果就是JVM转到sayHello的代码区,一步步执行。
public class HelloWorld {
private String name = "";
public HelloWorld(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public void sayHello(HelloWorld to, String msg){
System.out.println(to.getName()+" 收到 "+name+" 的消息:"+ msg);
}
}
public class OOPInvoke {
public static void main( String[] args ) {
HelloWorld person1 = new HelloWorld("Person1");
HelloWorld person2 = new HelloWorld("Person2");
person1.sayHello(person2,"Hello world");
}
}
sayHello在一个线程中执行基本没有问题,但是多个线程执行时,就可能出问题了,因为在执行sayHello的时候person2的name值可能被其他线程修改。这是一个name字段,意外修改没有关系,但如果是一个金额字段呢?
actor和对象的不同之处在于,actor的状态不能直接读取、修改,actor的方法不能直接调用。actor只能通过消息传递的方式与外界通信。每个对象都有一个this指针,代表对象的地址,可以通过该地址调用方法或存取状态;与此类似,actor也有一个代表本身的地址,但只能向该地址发送消息。
简单点说,actor通过消息传递的方式与外界通信。消息传递是异步的。每个actor都有一个邮箱,该邮箱接收并缓存其他actor发过来的消息,actor一次只能同步处理一个消息,处理消息过程中,除了可以接收消息,不能做任何其他操作。前面这段话,我加粗、倾斜、加下划线、还用红色字体标出,你就应该知道有多重要了,这就是actor模型的本质。

Actor模型的另一个好处就是可以消除共享状态,因为它每次只能处理一条消息,所以actor内部可以安全的处理状态,而不用考虑锁机制。标红的这两句话如果可以理解透彻,基本上Actor模型的精髓你就掌握了。
那么读者可能会问,每次只处理一个消息,这不是会严重的影响性能么?废话,一次处理一个消息当然影响性能了。不过,如果你恰当的运用Akka和Actor模型,完全可以不必关心性能的问题。下面是Actor模型的几个基本原则:
(1)所有的计算都是在actor中执行的
(2)actor之间只能通过消息进行通信交流
(3)为了响应消息,actor可以进行下列操作
a. 更改状态或行为
b. 发消息给其他actor
c. 创建有限数量的子actor
看了上面几个基本原则,你是不是更加鉴定的认为Actor模型没啥用?嗯,这就对了,因为我当初也是这么认为的。一次处理一个消息,没有并发,怎么提高性能;如果actor只能更改状态或行为,发消息给其他actor,创建有限数量的子actor,那我的业务逻辑在哪里;actor之间只能通过消息通信,我怎么知道另外一个actor的地址。其实吧,如果你能问到这几个问题,那么恭喜你,你非常需要我这个博客系列,我会一一进行分析,把我之前的坑展示给你看,以确保你不会再掉进去。
其实Actor模型出现的很早,而20世纪80年代,爱立信在Erlang中实现了Actor模型,用于嵌入式电信应用程序。该实现中引入了监督机制提供的容错性概念。爱立信使用Erlang和Actor模型实现了一款日后经常被提及的应用:AXD301。这玩意儿能提供99.9999999% 的可用性,看到没,7个9!!!绝对可以亮瞎人们的狗眼,这意味着在100年的时间中,AXD301只有3.1秒的时间会宕机。
Actor模型的另一个重要的特性就是容错,它通过监督机制提供容错。这跟java中的throw exception有点类似,都是把处理响应错误的责任交给出错对象以外的实体。但在java中如果一个程序或者线程抛出了一个异常,你敢放心的恢复对应的程序或线程吗?你确保恢复之后还能正常的运行吗,毕竟需要很多资源需要重新创建。但Actor模型可以!

如上图所示actor之间是有层级关系的,子actor如果出现了异常会抛给父actor,父actor会根据情况重新构建子actor,子actor从出现异常,到恢复之后正常运行,这段时间内的所有消息都不会丢失,等恢复之后又可以处理下一个消息。也就是说如果一个actor抛出了异常,除了导致发生异常的消息外,任何消息都不会丢失。这容错性当然好了。当然了,为了实现这种特性,akka或者Erlang需要做很多工作的。
Akka中的Actor模型还有另外一个比较重要的两个特性:分布式与位置透明性。其实可以认为这是一个特性。Actor模型中一个很重要的概念就是actor地址,因为其他actor需要通过这个地址与actor进行通信。akka考虑到分布式的网络环境,对actor地址进行了抽象,屏蔽了本地地址和远程地址的差异,对于开发者来说基本上是透明的。由于actor地址是透明的,那么akka有引入了集群。当然了基于Actor模型和位置透明性,Akka还有其他很多有用的组件,这里就不介绍了,后面会详细说明。
关于Actor模型就先介绍到这里,下一章节我们会介绍Actor模型的最基本的设计模式,以说明该模型的适用场景。
akka设计模式系列(Actor模型)的更多相关文章
- akka设计模式系列-消息模型(续)
在之前的akka设计模式系列-消息模型中,我们介绍了akka的消息设计方案,但随着实践的深入,发现了一些问题,这里重新梳理一下设计方法,避免之前的错误.不当的观点给大家带来误解. 命令和事件 我们仍然 ...
- akka设计模式系列-actor锚定
actor锚定模式是指使用actorSelection对acor进行锚定的设计模式,也可以说是一个对actor的引用技巧.在某些情况下,我们可能需要能够根据Actor的path锚定对应的实例.简单来说 ...
- akka设计模式系列-消息模型
通过前面的文章我们总结了几个常见的actor设计模式,但此处不得不提前介绍一下在Akka中消息的设计模式.随着对Akka的使用,我们会发现,使用Akka设计系统其实就是面向消息编程.actor之间消息 ...
- akka设计模式系列
由于本人爱好Scala,顺便也就爱好Akka,但目前网上对Akka的介绍大多都是概念上或技术方向上的介绍,基本没有Akka设计模式或者Actor模型设计模式的资料.这对于Akka的普及非常不利,因为即 ...
- akka设计模式系列-慎用ask
慎用ask应该是Akka设计的一个准则,很多时候我们应该禁用ask.之所以单独把ask拎出来作为一篇博文,主要是akka的初学者往往对ask的使用比较疑惑. "Using ask will ...
- Akka简介与Actor模型
Akka是一个构建在JVM上,基于Actor模型的的并发框架,为构建伸缩性强,有弹性的响应式并发应用提高更好的平台.本文主要是个人对Akka的学习和应用中的一些理解. Actor模型 Akka的核心就 ...
- akka设计模式系列-While模式
While模式严格来说是while循环在Akka中的合理实现.while是开发过程中经常用到的语句之一,也是绝大部分编程语言都支持的语法.但while语句是一个循环,如果循环条件没有达到会一直执行wh ...
- Akka简介与Actor模型(一)
前言...... Akka是一个构建在JVM上,基于Actor模型的的并发框架,为构建伸缩性强,有弹性的响应式并发应用提高更好的平台.本文主要是个人对Akka的学习和应用中的一些理解. Actor模型 ...
- akka设计模式系列-Backend模式
上一节我们介绍了Akka使用的基本模式,简单点来说就是,发消息给actor,处理结束后返回消息.但这种模式有个缺陷,就是一旦某个消息处理的比较慢,就会阻塞后面所有消息的处理.那么有没有方法规避这种阻塞 ...
随机推荐
- 关于C++中字符串输入get与getline的区别
最近使用C++中自己老是忘记的一个点,get与getline的区别. 1.get与getline get和getline所属iostream类,作用是读取一整行,通过换行符确定读取结束,他们都可以读取 ...
- <MySQL>入门四 事务控制语言 TCL
-- TCL /* Transcation Control Language 事务控制语言 事务:一个或一组sql语句组成一个执行单元,这个执行单元要么全部执行,要么全部不执行 案例:转账 name ...
- 微信小程序 setData动态修改数据数组的值
1.问题说明 有一组数据,用来存储图片路径,动态修改图片的路径来上传图片,而小程序JS只能通过事件获取时机和setData方法修改数据来改变view. 而用这样写的方式明显是错误的 2.解决办法 字符 ...
- linux内核开发程序风格
变量命名法 这里是linux不是windows,所以匈牙利命名法是不允许使用的,在内核中,局部变量只要可以明确表达自己的意思,可以使用idx,i这种名字的id, 全局函数和变量需要有表达性的名字例如g ...
- instance_name,db_name,oracle_sid之间的关系
一]对ORACLE_SID的理解 --------------------------------------------------------------------------------Ora ...
- java---括号匹配
import java.util.HashMap;import java.util.LinkedList;import java.util.Map; /* *括号匹配 * 1.用栈实现,如果读取字符为 ...
- Delphi语法
类与对象 从用户角度考虑,用户并不需要了解面向对象编程的知识,就可编写Delphi应用程序.当用户在建立新窗体.添加新组件以及处理事件时,大部分相关代码会由Delphi自动产生.但是,知道语言及其细节 ...
- Thinkphp 批量更新方法 saveALL
批量更新只适用于一个字段的更新,原理是用自定义函数拼接sql语句,然后再执行sql语句. //数据 $data[] = array('id'=>1,'value'=>value1); $d ...
- 【Codeforces 484A】Bits
[链接] 我是链接,点我呀:) [题意] 让你求出l~r当中二进制表示1的个数最多的数x [题解] 最多有64位 我们可以从l开始一直增大到r 怎么增大? 找到l的二进制表示当中0所在的位置 假设i这 ...
- RMI分布式议程服务学习
转自:http://6221123.blog.51cto.com/6211123/1112619 这里讲述的是基于JDK1.5的RMI程序搭建,更简单的说是一个 HelloWorld RMI. 1. ...