对于actor模型的思考

Actor 模型

Actor 模式是一个解决分布式计算的数学模型,其中 Actor 是基础,它能回应接收到消息,能够自我决策,创建更多的 Actor,发送更多的消息,决定如何回应下一个接收到的消息。Actor 认为一切皆是 Actor,类似于面向对象认为一切皆 Object 一样。OO 的执行是顺序的,Actor 模型内在设计就是并行的。

Actor 是异步的

Actor 是计算实体,它回复接收到的消息,能够并行的:

  • 发生有限的消息给其他 Actor
  • 创建有限数目的新 Actor
  • 指定一个消息到达时的行为

这些操作并没有顺序要求,它们能够并行地实施。由于没有对消息的时序做规定,Actor 模式是一种异步模型,发送到 Actor 不等待消息被接收而继续执行。Actor 之间不共享状态,如果想获取其他 Actor 的状态,只能通过消息请求的方式

Actor 在消息内部指定接收消息的 Actor 地址。Actor 可以用自己的地址发送消息,相当于自己接收到自己发送的消息,可以驱动自己的状态。

真正的 Actor 模型

Actor 可以被认为是在用户空间实现的并发实体,所以它应该是应用级别的线程。如果认同这个观点,那么 Actor 要满足的要求 = 操作系统对进程/线程 提出的要求一样。

内存结构

每个并发实体都是要有一个固定的数据结构,必须有一个容器可以保存当前所有的并发实体。这一点基本上很容易满足,Akka 中 Actor 就是一个类,所以它的结构就是这个类的数据结构,大小也就是这个类的大小。Akka 中的 Dispatcher 保存有所有 Actor 的列表。

并发原语

操作系统的是通过临界区,锁来定义多线程共享数据模型的。在 Actor 中是通过消息来共享数据的。基于消息传递要求“数据只读”,你发送出去的数据再修改肯定就不对了。Scala中容易实现,但是在 Java 里面无论如何都是做不到的,你不修改变量的引用但是还可以修改变量里面的值,调用对象的方法。

调度

这是最重要的:没有调度,并发实体根本不能称之为并发实体。操作系统中 CPU 是由内核管理的,调度算法是基于时间片来调任务的,内核随时可以剥夺一个任务的 CPU 使用权这就是“抢占”。这一点非常重要,没有这个功能就意味着调度是不公平的。一个任务耗费大量 CPU 会把另个一任务给饿死。但是在用户空间(应用层)很难实现这一点,毕竟 CPU 是不受应用程序的控制的,没有把办法剥夺。抢占看似可有可无,但是没有它就没有“公平调度”,也就谈不上并发。(有任务撑死,有任务饿死)

所谓“公平调度”

比如写两个 Actor,使用无限循环输出字符串(while(true))会疯狂的吃 CPU,如果是可抢占的公平调度,则 actor1 和 actor2 应该是比较有规律的交替(大家得到的 CPU 时间差不多)

Scala/Java 中的 Akka

test1
test1
test1
...
test2
test2
test2
...
test1
...
1
2
3
4
5
6
7
8
9
10

ErLang

test1
test2
test1
test2
test1
test2
test1
test2
...
1
2
3
4
5
6
7
8
9

显而易见,ErLang 非常均匀的任务切换,实现了“可抢占的公平”

posted @ 2019-08-01 10:07  leon.sang  阅读(177)  评论(0编辑  收藏  举报