第七章 使用Akka构建高并发程序
- 提供了一种称为Actor的并发模型,其粒度比线程更小,因此可以在系统中大量使用Actor。不仅适用于单机,也适用于分布式程序。
7.1 新并发模型:Actor
- 在Actor模型中,失去了对象的方法调用,并不是通过调用Actor对象的一个方法告诉Actor需要做什么,而是给Actor发送一条消息。当Actor收到一条消息后,它可能会根据消息的内容做出某些行为,包括更改自身状态。但其状态修改是Actor自己进行的,而非外部调用的。
7.2 Akka之 Hello Word
- 在Akka中,UntypedActor就是所说的Actor。之所以强调无类型,是因为Akka中,还支持一种有类型的Actor,其可以使用系统其他类型构造,可以缓解java单继承的问题。
- 使用Actor进行并行程序开发时,关注点已经不在线程上,只需关注Actor对象即可,而Actor对象之间的交流和普通对象的函数调用有着明显的区别,它们是通过显示的消息发送来传递消息的。
- 当系统中有多个Actor存在时,Akka会自动在线程池中选择线程来执行actor,因此多个不同的Actor可能会被同一个线程执行,一个Actor可能被不同的线程执行。
7.3 有关消息投递的一些说明
- 整个Akka应用是消息驱动的。消息是Actor之外的重要核心组件,在Actor之间传递的消息应该满足不变性。因此,Akka中的消息推荐使用不可变对象,即final修饰的。
- 消息投递的三种策略:
- 至多一次投递。每一条消息最多会被投递一次,可能会导致消息投递失败,消息丢失
- 至少一次投递。每一条消息至少会被投递一次,直到成功为止。不会发生消息丢失,但是可能会发生消息重复
- 精确的消息投递。保证所有消息都会被成功投递一次,既不会有丢失也不会重复。
- 实际上,没必要在Akka层保证消息的可靠性,成本太高,也没有必要。消息的可靠性可以在应用层确保。
- 顺序性:在一定程度上保持消息的顺序性。如A1向A2顺序发送了M1、M2和M3,三条消息,A3向A2顺序发送了M4、M5和M6三条信息
- 如果M1没有丢失,那它一定先于M2和M3被A2收到
- 如果M2没有丢失,那它一定先于M3被A2收到
- 如果M4没有丢失,那它一定先于M5和M6被A2收到
- 如果M5没有丢失,那它一定先于M6被A2收到
- 对A2来说,来自A1和A3的消息可能交织在一起,没有顺序保证。消息的传递不具有传递性。如A向C发送了M1,接着,A向B发送了M2,B将M2转给了C,那么C收到M1和M2没有先后顺序保证
7.4 Actor的生命周期
- 一个Actor在actorOf函数被调用后开始建立,Actor实例创建后,会回调preStart方法。如果actor在工作过程中出现异常,需要重启,会回调preRestart方法(老的实例上),接着系统会创建一个新的actor实例,虽然是新的,但表示同一个actor,当新实例创建后,postRestart方法会被调用,表示启动完成。stop方法可以停止actor,其停止时,postStop会被调用,同时这个actor的监视者会收到Terminated消息。
7.5 监督策略
- 两种:
- OneForOneStrategy(默认策略)
- 父Actor只会对出问题的子Actor进行处理。
- AllForOneStrategy
- 父Actor会对所有的子都进行处理
7.6 选择Actor
- ActorSelection类可以根据path匹配规则,批量获取actor
7.7 消息收件箱(Inbox)
- 可以方便地对Actor进行消息发送和接收,大大方便了应用程序与Actor之间的交互。
7.8 消息路由
- 路由器组件,实现消息调度的封装。提供几种消息路由策略如,轮询选择actor进行消息发送,随机消息发送,将消息发送给最为空闲的actor,组内消息广播。
7.9 Actor的内置状态转换
- 一个actor内部消息处理函数可以拥有多个不同的状态,在特定的状态下,可以对同一条消息进行不同的处理,状态之间也可以任意切换。
7.10 询问模式:Actor中的Future
7.11 多个Actor同时修改数据:Agent
- 提供了对一个变量的异步更新。
7.12 像数据库一样操作内存数据:软件事务内存(STM)
- 具有隔离型、原子性和一致性。但不具有持久性。确保多个actor协作完成一项任务的问题。
7.13 一个有趣的例子:并发粒子群的实现
- 粒子群算法(PSO)是一种进化算法。与遗传算法非常类似,可以用来解决一些优化问题。可以将一些NP问题转变为一个多项式问题。但是有代价的,进化算法不保证可以从结果中得到最优解。
7.13.1 什么是粒子群算法
- 一种基于迭代的优化算法。广泛应用于函数优化与神经网络训练等方面。源于鸟类的觅食的群体表现。
7.13.2 粒子群算法的计算过程
- 初始化所有粒子,粒子的位置随机生成。计算每个粒子当前的适应度,并将此设为当前粒子的个体最优值(记为pBest)
- 所有粒子将自己的个体最优值发送给管理者Master。Master获得所有粒子的信息后,筛选出全局最优的解(记为gBest)
- Master将gBest通知所有粒子,所有粒子便知道全局最优点的位置
- 接着,所有粒子根据自己的pBest和全局gBest,更新自己的速度,在有了速度后,再更新自己的位置
- 如果粒子产生了新的个体最优点,则发送给Master,在此,转到步骤2
7.13.3 粒子群算法能做什么
- 最优化计算。
7.13.4 使用Akka实现粒子群
- 由于粒子数量过大,因此一般的线程模型无法满足,但Actor本身作为轻量级的并发单元,一个线程可以对应多个actor,因此适合进行这种并发计算。