我正在尝试理解 Actor 和线程定义的区别。
老实说,他们真的没有太多的关系,所以很难谈论他们的区别。这就像在谈论丰田凯美瑞和蓝色之间的区别。
Actor 是一个自包含、封装的实体,它与其他自包含、封装的实体完全通过发送消息进行通信。
现在,如果这听起来完全对你来说就像对象的定义,那么你是对的! Actors 和 Objects 之间有着深厚的联系:计算的 Actor 模型是由 Carl Hewitt 构思的,部分基于早期 Smalltalks 的消息导向执行(Smalltalk-71,Smalltalk-72)。 Alan Kay 反过来引用 PLANNER 的目标导向执行作为对 Smalltalk 的消息导向执行的重大影响……反过来,PLANNER 是由 Carl Hewitt 设计的。 (PLANNER 也是 Prolog 的前身,而 Prolog 又是 Erlang 的前身;Erlang 基于 Prolog,最初是作为 Prolog 中的一个库,第一个实现是用 Prolog 编写的。)此外,Carl Hewitt 和 Alan Kay引用 Vint Cerf 和 Bob Kahn 早期关于后来成为互联网的工作作为灵感,他们两人都深受大自然的启发,Carl Hewitt 的物理学和 Alan Kay 的微生物学。因此,深层联系和相似之处也就不足为奇了。
Actors 和 Objects 几乎是一回事。我们通常期望面向对象系统中的消息发送是同步的、瞬时的、可靠的和有序的,而对于 Actors 则不存在这样的保证。这是 Actor 和 Object 之间的主要区别:Actor 是消息可能会丢失、重新排序、需要很长时间并且是异步的对象。 (唯一的保证是消息可能会被传递最多一次。)此外,消息的接收者通常没有对发送者的隐式引用,所以如果接收者想要回复消息,发件人需要将自己的引用与消息一起传递(与典型的面向对象系统不同,我总是可以return 给发件人一些东西)。
Actor 可以做三件事,正是这三件事,仅此而已:
- 创建新的演员
- 将消息发送到它已经知道的 Actor 的地址(即它创建的 Actor 的地址,以及它在消息中发送的地址)
- 指定如何处理下一条消息(这本质上是如何为可变状态建模)
请注意,为了向 Actor 发送消息,您需要拥有 Actor 的地址。您只能向地址发送消息。一个Actor可能有多个地址,多个Actor可能隐藏在一个地址后面。地址是不可伪造的,你不能自己构建一个,你必须把它交给你。 (这是与 C 中的指针的一个重要区别,更像是 Java 中的对象引用。)
在 Microsoft 的 Channel9 社区网站上有一段非常精彩的视频,内容是 Carl Hewitt 本人和 Erik Meijer 之间关于演员的白板会议:Hewitt, Meijer and Szyperski: The Actor Model (everything you wanted to know, but were afraid to ask)。它以通俗易懂的方式解释了 Actor 背后的基本思想以及 Actor 的基本公理。
Carl Hewitt 还应邀在斯坦福大学的 EE380 计算机系统座谈会上发表演讲,他在会上谈到了 How to Program the Many Cores For Inconsistency Robustness,包括对 Actors 的介绍。
线程,OTOH 只是执行链。它们本质上只是一个指令指针和一个调用堆栈。特别是,线程没有(它们自己的)内存。一个进程的所有线程共享相同的内存。这意味着除其他外,单个行为不端的线程可能会使进程的所有个线程崩溃,并且必须仔细控制对该共享内存的所有访问。
有些文章说actors是轻量级线程,而另一些文章则说actors不是线程。我也明白一个线程可以运行多个actor。
您将 Actor 的概念与可能的实现混淆了。
Actor 在现有环境中的一个非常简单的实现是让每个 Actor 成为一个进程。例如,这就是 BEAM(Erlang 的主要实现)的工作原理。这是可行的,因为在 BEAM 上,流程非常便宜且轻量级;一个进程仅重300 Byte左右,10年前一台便宜的32位单核笔记本电脑上可以有上千万个进程。这不适用于 Windows 进程,例如,它们要贵得多。
还有一个在 JVM 上的 Erlang 实现(称为 Erjang),它使用 Kilim,这是一个在 JVM 上使用字节码重写的极其轻量级的 Actor 的实现。 (请注意,Erjang 和 Kilim 似乎都死了。)
如果你想在线程上实现Actor,你会遇到一个问题,即Actor是完全隔离的,而线程是完全共享的。因此,您需要以某种方式提供这种隔离。
在 JVM 等系统上实现 Actor 的常用方法是将 Actor 实现为对象,然后安排它们在线程池上运行以获取异步属性。这就是 Akka 的工作原理。