七周七并发模式:Actor

Posted by 蔡华的博客 on March 15, 2018

什么是Actor

  • 在本书提到的观点中,认为Actor是一个线程或者进程。在这个线程或者进程中执行了一段代码(函数),这个代码可以包含状态(数据)也可以不包含。

所谓Actor模型是Sequential Processes和Functions transforming data values两者的结合,可以理解为是综合了过程式计算和函数式计算的一个计算模型。

一个Actor会把接收到的消息映射为三个部分,传给其他Actor的消息,一个新的行为(用来处理下一个消息),和创造一些新的Actors。

为什么会出现Actor

  • 在本书的第二章谈到了线程和锁,其中提到了这个并发模式存在的一些问题,比如竞争共享资源所导致的阻塞、多重锁导致的死锁等问题。
  • Actor正是为了解决这些问题而产生的。从定义看actor就是多线程,只不过它避免了对于共享资源的并发调用。一个actor只使用自己的资源,而不是直接使用共享资源,它作用单一,顺序执行。不同的Actor之间使用message来传递数据。
  • PS:这里实际上并不存在真的不使用锁。只要存在多个actor共同访问一个数据对象就存在锁的问题,只不过可能无需开发者自己去写相关的代码。因此书中在提到actor缺点时也提到了可能出现死锁的问题。
  • PS2:在书中最后使用Actor来统计wiki的例子里,实际上是将wiki的页面进行拆分,然后不同的page用不同的Actor开统计。

消息和信箱

  • 因为actor模型没有提供直接回复消息的机制,所以将发送进程的标识符包含在消息中。通过这个机制,消息的接收者可以回复消息。
  • 异步地发送消息是用actor模型编程的重要特性之一。消息并不是直接发送到一个actor,而是发送到一个信箱(mailbox)。
  • 每个Actor都有一个信箱

分布式

  • 与其说Actor是为了并发,不如说Actor是为了分布式。
  • 书中使用Elixir语言进行了demo的编写。在不同的设备或者操作系统中(这里可以是一个设备上有多个不同的虚拟机,也就是逻辑意义上的一个主机),不同的Actor可以进行通信,可以协作来处理一些数据。整个过程是异步的,每个Actor因为都看上去是无状态的,或者说即使有状态也是内部的。所以每个Actor的运行并不会影响其它Actor。

Actor的实现

  • 这个是我比较郁闷的地方,因为书中使用了Elixir这个我完全不熟悉的语言,因此我对于代码也是看个大概,具体某些语法和函数为什么这么写也是一知半解。
  • 但是从demo code来看,也是创建纤程(这个概念个人认为和golang里面的应该是一样的)来实现actor,而一个actor本质就是一个module,里面包含了一些函数用于处理逻辑,收发消息。
  • 对于Actor可以使用缓存机制来统一进行管理。这样的好处还有可以控制错误的处理。

Actor的错误处理

  • 书中对于Actor的错误处理有这样一个观点:任其崩溃。
  • 这个观点得益于Actor的独立性,在一个Actor出现异常后,以为它对于某些消息的处理是失败的,因此消息队列或者信箱可以将没有处理的消息交给其它的Actor来处理。
  • 出现异常的Actor什么我们可以不做任何的处理。
  • 不过如果出现Actor一启动就崩溃了,那么也不能无限制的创建新的Actor。因此书中提到了Actor创建频率的问题,过高的时候就要考虑错误的问题了。
  • 对于Actor的错误处理建议的做法是创建一个错误处理内核,这就有一个要求了:那么该系统正确运行的前提是其错误处理内核必须正确运行
  • 如何保证错误处理内核正确运行呢?这需要内核是顶层的管理者,书中是使用actor的缓存来实现的。

image

  • 同时在错误处理时还要保证消息的必达性:
    • 没有异常发生,消息一定能被送达并被处理
    • 如果某个环节出现异常,异常一定会通知到使用者(假设使用者已经连接到或正在管理发生异常的进程)

Actor的优势和缺点

  • 从前面的讲述来看,其优点是:
    • 消息的传输和封装性很好
    • 容错能力比较好
    • 天然支持分布式。
  • 而缺点是:
    • 同样有死锁问题
    • 信箱溢出(这个可能是指的actor如果处理不够及时,mailbox可能会数据量过大)
    • actor本身没有直接提供并发,需要通过并发技术来构造并发方案。
    • 由于多个actor并不共享状态,仅通过消息传递来进行交流,所以不太适合实施细粒度的并行。

吐槽

  • 这本书是好书,不过其使用的编程语言确实比较丰富,导致我看代码时很痛苦。
  • 像是OTP部分完全是依赖于某个编程语言来写的,对于其真正的机制我觉得描述的不够清楚。

参考