如前一主题「为什么现代系统需要新的编程模型」所述,常见的编程实践不能合适地满足现代系统的需求。幸运的是,我们不需要放弃我们所知道的一切。相反,Actor 模型以一种原则性的方式解决了这些缺点,允许系统以更好地匹配我们的构思模型(mental model
)的方式运行。Actor 模型抽象允许你从通信的角度来考虑你的代码,这与大型组织中人员之间发生的交换没有什么不同。
使用 Actor 允许我们:
world view
)不匹配。Actor 不调用方法,而是互相发送消息。发送消息不会将线程的执行权从发送方传输到目标方。Actor 可以发送一条消息并继续其他操作,而不是阻塞。因此,它可以在相同的时间内完成更多的工作。
对于对象,当一个方法返回时,它释放对其执行线程的控制。在这方面,Actor 的行为非常类似于对象,它们对消息作出反应,并在完成当前消息的处理后执行返回。通过这种方式,Actor 实际上实现了我们设想中对象的执行方式:
传递消息和调用方法之间的一个重要区别是消息没有返回值。通过发送消息,Actor 将工作委托给另一个 Actor。正如我们在「调用栈的假象」中看到的,如果它期望返回值,那么发送 Actor 要么阻塞,要么在同一线程上执行另一个 Actor 的工作。相反,接收 Actor 在回复消息中传递结果。
我们模型中需要的第二个关键改变是恢复封装。Actor 对消息的反应就像对象对调用它们的方法“反应”一样。不同之处在于,不同于多个线程“突出(protruding
)”到 Actor 中并对内部状态和不变量造成严重破坏,Actor 的执行动作独立于消息的发送者,并对传入消息依次作出反应,一次一个。当每个 Actor 按顺序处理发送给它的消息时,不同的 Actor 同时工作,以便 Actor 系统可以同时处理硬件所支持的尽可能多的消息。
由于每个 Actor 最多只能同时处理一条消息,因此可以不同步地保留 Actor 的不变量。这是自动发生的,不使用锁:
总之,当 Actor 收到消息时会发生以下情况:
unscheduled
)。为了完成上面的行为,Actors 有:
消息进入 Actor 邮箱。Actor 的行为描述了 Actor 如何响应消息(如发送更多消息和/或更改状态)。执行环境协调线程池以完全透明地驱动所有这些操作。
这是一个非常简单的模型,它解决了前面列举的问题:
由于我们不再拥有在相互发送消息的 Actor 之间共享的调用栈,因此我们需要以不同的方式处理错误情况。我们需要考虑两种错误:
一个监督者(父级节点)可以决定在某些类型的失败时重新启动其子 Actor,或者在其他失败时完全停止它们。子 Actor 永远不会默不作声地死去(除了进入一个无限循环之外),相反,他们要么失败,他们的父级可以对错误作出反应,要么他们被停止(在这种情况下,相关方会被自动通知)。总是有一个负责管理 Actor 的实体:它的父节点。从外部看不到重新启动:协作 Actor 可以在目标 Actor 重新启动时继续发送消息。
现在,让我们简单介绍一下 Akka 提供的功能。
英文原文链接:How the Actor Model Meets the Needs of Modern, Distributed Systems.