文章目录
- 0 引入
- 1、理解
- 1.1 为什么会出现Actor这种模型呢?
- 1.2 Actor如何解决
- 2、应用
- 1.SkyNet
- 2.Erlang
- 3.RabbitMQ
- 3、引用
0 引入
最近发现Actor模型其实我在工作中已经不知不觉实现了,最起码有这些影子。
1、理解
Actor模型是一种轻量级的并发编程模型,它将并发程序看作是一组相互独立的、互相发送消息的Actor(类似于面向对象编程中的对象),每个Actor都有自己的状态和行为,它们之间通过异步消息传递进行通信,Actor模型非常适用于多个组件独立工作,相互之间仅仅依靠消息传递的情况
特点:
- 更加面向对象:Actor类似面向对象编程(OO)中的对象,每个Actor实例封装了自己相关的状态,并且和其他Actor处于物理隔离状态
- 无锁:每个Actor之间通过消息传递信息,多个线程在执行共享资源需要特别的关注锁和内存原子性等一系列线程问题,而Actor模型内部的状态由它自己维护即它内部数据只能由它自己修改(通过消息传递来进行状态修改),所以使用Actors模型进行并发编程可以很好地避免这些问题。Actor内部是以单线程的模式来执行的;
- 异步:actor根据消息队列处理自己的逻辑;
- 隔离:每个actor都是独立的个体;
- 分布式:消息驱动(或者事务驱动);
- 缺点:由于是分布式,群体的集合信息搜集不是他的强项,需要统一强实时性也有点不好实现(因为是异步结构)。
1.1 为什么会出现Actor这种模型呢?
以银行的账户为例子,最基本功能:存钱和取钱,那么对于一个账户来说存钱和取钱不能同时是进行,需要加一个锁(或者其他能够保证资源只能被唯一占有方法都行),保证账户安全性。
这个锁虽然保证了账户的安全性,但是确实花费了存钱和取钱的效率;
再往下看:旺财的账户A向小强B账户转账:先从账户A取钱(锁住),在向B账户存钱(锁住),只有这两项都成功,这个转账才生效(属于严格的原子操作),在解锁执行后续操作。。。
如果同时,旺财的账户A向小强B账户转账,小强B账户转账向 旺财的账户A 这就会出现死锁的可能,当然通过排序也可以解决这个过程,但是浪费时间。
1.2 Actor如何解决
(从引用截了一张图)
从上面给可以看出,引入一个第三方转账管家(也可以认为是统一消息管理者),小强和旺财想要做的事情通过Message传给他。再有他把事情安排安排下去,当然这里如何保证转账的原子性,那就需要有一个事务追踪(标记)。
此时就有一个问题,如果转账失败需要回滚,那么整个Actor处理的话就比较麻烦了
所以再此基础上,可以将整个系统添加一些管理者:
1、建立一个Actor管理者,负责监控Actor的创建销毁;
2、可以额外增加一个错误/日志消息管理者;
…
这些都是根据实际系统架构需求来补充,让整个流程更流畅,避免公共资源的使用。
2、应用
1.SkyNet
- 游戏界有名的编程大神云风,(《西游》了解一下,我也看过他写的那本《游戏之旅——我的编程感悟》)
云风的skynet,定义为一个游戏服务器框架,用C语言,(一开始的第一版基于Erlang实现)
lua(其实这个框架在早期的类传奇类游戏大部分使用这个)基于Actor模型实现。代码极其精简,c部分的代码只有三千行左右。 - 整个skynet框架要解决的核心问题是:把一个消息(数据包)从一个服务(Actor)发送给另一个服务(Actor),并接收其返回。也就是在同一进程内(作者也强调并非只限于同一进程,因为可能会有集群间的通讯)的一个服务通过类似rpc之类的调用同一进程内的另外一个服务,并接收处理结果。而skynet就是处理这些服务间发送数据包的规则和正确性。
- 源码网上已经开源,github有,感兴趣可以去阅读。
2.Erlang
- 1998年Erlang开源,2006年传入国内C++程序员圈,Erlang China User
Group始于2007,现改名为Effective Cloud User Group - 并行和分布式
Erlang采用的Actor模式使其增长并行处理,错误处理机制和储存管理为分布式服务,Erlang并不擅长存储密集型数值计算。
3.RabbitMQ
- RabbitMQ是一个由erlang开发的AMQP(Advanced Message Queue 高级消息队列协议 )的开源实现,
能够实现异步消息处理 - RabbitMQ是一个消息代理:它接受和转发消息。
-典型的使用场景: 在我们秒杀抢购商品的时候,系统会提醒我们稍等排队中,而不是不去响应出现卡死现象。
3、引用
1、深入理解Akka actor模型
2、分布式计算(3):分布式计算模式之Actor
3、Actor——Actor模型原理的通俗理解 (转)
4、从0到1用c++实现一个Actor模型