Actor

Actor

20 世纪 70 年代 Carl Hewitt 首次提出了 Actor 模型,而后 Erlang 为布道 Actor 做了最大的贡献,比如 Erlang 的创始人 Joe Armstrong 也是“任其崩溃”哲学的先驱。Actor 模型可以看做面向对象模型在并发编程领域的扩展,其精心设计了消息传输和封装的机制,强调了面向对象的精髓。Actor 模型是一个概念模型,用于处理并发计算。

Actor 是分布式存在的内存状态及单线程计算单元,一个 ID 对应的 Actor 只会在集群种存在一个(有状态的 Actor 在集群中一个 ID 只会存在一个实例,无状态的可配置为根据流量存在多个),使用者只需要通过 ID 就能随时访问不需要关注该 Actor 在集群的什么位置。单线程计算单元保证了消息的顺序到达,不存在 Actor 内部状态竞用问题。

特性

并发

Actor 有许多优良的特性,适用于解决多种并发问题。消息传输和封装虽然多个 Actor 可以同时运行,但它们并不共享状态,而且在单个 Actor 中所有事件都是串行执行的。所以关于并发,只需要关注于多个 Actor 之间的消息流即可。对开发人员来说这是个重大利好。每个 Actor 可以被单独测试,而且当测试覆盖了某个 Actor 的消息类型和消息顺序时,就可以确定这个 Actor 非常可靠。如果发现了一个与并发相关的 bug,也就知道重点应该放在 Actor 之间的消息流上。

使用 Actor 模型的程序天生具有容错性。这不仅会让程序更加强壮,而且(通过“任其崩溃”的哲学)会让代码更加简洁明了。

Actor 模型支持共享内存模型,也支持分布式内存模型,这就带来了很多优点。首先, Actor 模型几乎可以解决任何规模的问题。我们不需要将问题局限于用一个系统解决。其次, Actor 模型可以解决地理分布式问题。对于不同部分需要部署在不同地理位置的软件,Actor 模型是个极佳的选择。最后,分布式是软件具有容错能力的基石。

尽管使用 Actor 模型的程序比使用线程与锁模型的程序更容易 debug,但 Actor 模型仍会碰到死锁这一类的共性问题,也会碰到一些 Actor 模型独有的问题(例如信箱溢出)。

类似于线程与锁模型, Actor 模型对并行也没有提供直接支持。需要通过并发的技术来构造并行的方案,这样就会引入不确定性。而且,由于多个 Actor 并不共享状态,仅通过消息传递来进行交流,所以不太适合实施细粒度的并行。

案例

模型组成

Actor 由 3 部分组成:状态(State)+行为(Behavior)+邮箱(Mailbox),State 是指 Actor 对象的变量信息,存在于 Actor 之中,Actor 之间不共享内存数据,Actor 只会在接收到消息后,调用自己的方法改变自己的 state,从而避免并发条件下的死锁等问题;Behavior 是指 Actor 的计算行为逻辑;邮箱建立 Actor 之间的联系,一个 Actor 发送消息后,接收消息的 Actor 将消息放入邮箱中等待处理,邮箱内部通过队列实现,消息传递通过异步方式进行。