绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
不一样的并发编程:Actor 并发编程模型
2019-09-20 08:57:38

传统的并发编程我们都很熟悉,以 Java 举例,那就是通过共享内存和锁的方式来进行并发控制。但你有没有想过还有其他方式可以实现高并发呢?今天我们就来看看 Actor 并发编程模型,并从一致性和隔离性的角度来分析为什么有 Actor 并发编程模型。


一.Actor模型介绍

在单核 CPU 发展已经达到一个瓶颈的今天,要增加硬件的速度更多的是增加 CPU 核的数目。而针对这种情况,要使我们的程序运行效率提高,那么也应该从并发方面入手。传统的多线程方法又极其容易出现 Bug 而难以维护,不过别担心,今天将要介绍另一种并发的模式能一定程度解决这些问题,那就是 Actor 模型。

Actor 模型其实就是定义一组规则,这些规则规定了一组系统中各个模块如何交互及回应。在一个 Actor 系统中,Actor 是小的单元模块,系统由多个 Actor 组成。每个 Actor 有两个东西,一个是 mailbox,一个是自身状态。同时 Actor 有接收和发送的功能。下面用 scala 代码给出一个大概的 Actor 样例:当一个 Actor 接收到消息后,它会执行下面三种操作中的一种:

创建其他 Actors。

向其他 Actors 发送消息。

修改自身状态。

需要注意的是,尽管许多 Actors 同时运行,但是一个 Actor 只能顺序地处理消息。也就是说其它 Actors 发送了三条消息给一个 Actor,这个 Actor 只能一次处理一条。所以如果你要并行处理3条消息,你需要把这条消息发给3个 Actors。

下面这张图展示了一个简单的 Actor 模型系统:

了解了 Actor 模型的大概规则后,我们用两个具体的例子来看看 Actor 模型的妙处以及不足吧。

二. 两个例子

2.1 素数计算

假设我们现在有一个任务,需要找出100000以内素数个数,并且使用多线程的方式实现。

下图展示了使用共享内存的方式和以Actor模型的方式进行并发执行。

这里展示了两种处理并发的不同思路,传统的方式是通过锁/同步的方式来实现并发,每次同步获取当前值,并让一个线程去判断值是否为素数,是的话再通过同步的方式对计数器加1(这里的说明只是作为提供思路用,这种方法自然有很大的优化空间)。

而使用 Actor 模型则不一样,它将这一过程拆分成几个模块,即拆分成几个 Actor 。每个 Actor 负责不同的部分,通过消息传递的方式让这几个 Actor 协同工作,并且其中涉及到主要计算的 Actor 可以有多个,通过多个 Actor 协同工作实现并发。

2.2 银行转账

银行转账的任务描述很简单,假设有两个用户,现在用户A向用户B转账100元,这个 Actor 模型该如何设计呢?

用户 A 和 用户 B 明显是两个 Actor ,但我们同时还需要一个可以控制用户A Actor 和用户B Actor 的 Actor ,我们称之为 转账管家 Actor。那么流程图如下。

可以看到,当一个转账需求过来的时候,Actor 管家会先向 用户A Actor 发送扣款 100 元的信息,接受到扣款成功消息后再发送消息给用户B Actor,发送让其增加 100 元的消息。


一切看起来都很美好是吧,但这里面有一个问题,那就是在用户A Actor 扣款期间,用户B Actor 是不受限制的,此时对用户B Actor 进行操作是合法的!举个例子你就明白了,假设 A 向 B 转账 100 元,这在一致性强的环境下, A 账户减少 100 ,B 账户增加 100 ,然后 B 才能转账给别人。而在 Actor 中,可能 A 减少了 100 之后,B 还没增加 100,这时候 B 又向 C 转账 50,B 的账户会先减少 50 ,而后再增加 100,这就很容易发生一些脏读,幻读等问题。对这种情况单纯的Actor模型就显得比较乏力了,需要加入其他机制以保证一致性。

看到这你就明白了,Actor 模型并非的,它有一定的缺点。那就是针对一致性要求比较强的场景比较乏力。

三. 为什么会出现 Actor 模型

在聊为什么之前,我们需要先说说事物并发中的 一致性 和 隔离性 。

一致性即让数据保持一致,比如银行转账例子中,用户A 转给用户B 100块钱,没有其他干扰的情况下,转账完成时。用户A 的账户必然减少 100 元,用户B 的账户必然增加100 元,这就满足了一致性。不能说用户A 减少50 或用户B 增加了 200。

隔离性可以理解为牺牲一部分的一致性需求,而获得性能的提高。打个比方,在完全一致的情况下,任务都是串行的,这时候也就不存在隔离性了。

明白这些之后,你就直到为什么会有 Actor 模型了。

传统并发模式,共享内存是倾向于强一致性弱隔离性的。比如悲观锁/同步的方式,其实就是使用强一致性的方式控制并发。而Actor 模型天然是强隔离性且弱一致性,所以 Actor 模型在并发中有良好的性能,且易于控制和管理。


这样你就明白 Actor 模型适合于什么样的并发场景了,当对一致性需求不是很高的情况下且对性能需求较高时,Actor 模型无疑是一个值得尝试的方案。 比如现在诸多分布式框架中(Hadoop,Spark等),他们之间的 RPC 通信就多是用 Actor 模型而非传统的并发编程来实现。

分享好友

分享这个小栈给你的朋友们,一起进步吧。

应用开发
创建时间:2020-06-17 15:31:04
应用软件开发是指使用程序语言C#、java、 c++、vb等语言编写,主要是用于商业、生活应用的软件的开发。
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • 栈栈
    专家
戳我,来吐槽~