3

Joe Armstrong 的论文中,他指出应该通过以下三个步骤来设计基于 Actor 的程序。问题是,我不明白这些步骤如何映射到现实世界的问题或如何应用它们。这是乔的原始建议。

  1. 我们在现实世界的活动中识别出所有真正并发的活动。
  2. 我们识别并发活动之间的所有消息通道。
  3. 我们写下所有可以在不同消息通道上流动的消息。现在我们编写程序。程序的结构应该完全遵循问题的结构。在我们的编程语言中,每个现实世界的并发活动都应该映射到一个准确的并发进程上。如果问题与程序有 1:1 的映射,我们就说程序与问题同构。

映射恰好是 1:1,这一点非常重要。这样做的原因是它最小化了问题和解决方案之间的概念差距。如果这个映射不是 1:1,程序会很快退化,变得难以理解。当使用非 CO 语言解决并发问题时,通常会观察到这种退化。通常,让程序工作的唯一方法是强制几个独立的活动由同一个语言线程或进程控制。这导致不可避免的清晰度损失,并使程序受到复杂且不可重现的干扰错误的影响。

我认为#1很容易弄清楚。这是我迷路的#2(和3)。为了说明我的挫败感,我删除了这个 gist 中提供的一个小服务(带有回调的 Ruby 服务)。

查看该示例服务,我可以看到如何回答 #1。我们有 5 个并发服务。

  1. 开始
  2. 登录网关
  3. 注销网关
  4. 停止
  5. 订阅

根据服务所处的状态,其中一些服务不起作用(或不应该)。如果服务尚未启动,那么登录/注销/订阅就没有任何意义。这种状态信息与乔的 3 步有什么关系吗?

无论如何,鉴于该要点中的示例/模拟服务,我想知道有人将如何设计一个程序以以 Actory 方式包装该服务。我只想查看有关如何应用 Joe 的 3 个步骤的指南列表。编写一些代码(任何语言)的奖励积分。

4

1 回答 1

9

通常,在构建应用程序以使用参与者时,您必须识别应用程序的并发特性,这可能很难掌握。您确定了 5 个并发“服务”:

  1. 开始
  2. 登录网关
  3. 注销网关
  4. 停止
  5. 订阅

1、4和5似乎是可以流经系统的消息类型,2和3我不知道如何描述。你的要点相当大,对我来说不是清楚,但看起来你有某种消息队列系统。用户可以采取的行动是:

  1. 登录系统
  2. 登出系统
  3. 订阅消息队列

我假设登录和注销需要一些身份验证步骤。我将进一步假设,如果用户未能通过身份验证步骤,他们的连接就会中断,但创建连接并不足以进行身份​​验证。

系统采取的行动是:

  1. 处理用户操作
  2. 将消息路由到队列的订阅者

如果这不是普遍正确的,请告诉我,我会更改此答案。(我假设发送给用户的消息不是由用户生成的,而是系统的固有部分;也许我们正在讨论监视服务。)无论如何,这里的并发是什么?一些东西:

  1. 用户彼此独立行动
  2. 队列有不同的状态

基于参与者的架构将每个并发实体表示为其自己的进程。用户是一个有限状态机,它进行身份验证、订阅队列、交替接收消息并订阅更多队列并最终断开连接。在 Erlang/OTP 中,我们用gen_fsm来表示它。User进程携带与客户端交互所需的所有状态,如果我们通过网络公开服务,则它将是一个套接字。

身份验证意味着系统本身就是一个“进程”,不过,它很可能实际上是进程的集合,在 Erlang/OTP 中我们称之为应用程序。我跑题了。为简化起见,我们假设System本身是一个单独的进程,它具有一些定义良好的协议和一个保存用户凭据的状态。因此,用户登录是从用户进程到系统进程 明确定义的消息以及来自那里的响应。如果没有身份验证,我们就不需要系统进程,因为与用户相关的唯一状态是套接字。

细心的读者会问我们在哪里接受每个用户的套接字连接?啊,好问题。还有一个没有提到的并发实体,我们在这里称之为Listener。这是另一个监听连接的进程,为每个新建立的套接字创建一个用户并将所有权移交给新的用户进程,然后循环监听。

队列也是一个有限状态机。从它的启动状态开始,它通过定义明确的协议接受用户订阅请求,向订阅者广播消息或接受来自用户进程的取消订阅请求。这意味着队列有一个用户进程的内部存储,其细节非常依赖于语言和需求。例如,在 Erlang/OTP 中,每个Queue进程都是一个gen_server,它在列表中存储用户进程 id(或 PID),并且对于要传输的每条消息,只需向列表中的每个用户进程进行多发送。

(在 Erlang/OTP 中,我们需要用户监督者来确保进程保持活动状态并在死亡时重新启动,这极大地简化了 Erlang 开发人员为确保基于参与者的架构中的可靠性而必须做的工作量。)

基本上,为了重申 Joe 所写的内容,基于演员的架构可以归结为以下几点:

  • 识别系统中的并发实体并在流程的实现中表示它们,
  • 决定您的进程将如何发送消息(Erlang/OTP 中的原始操作,但必须在 C 或 Ruby 中显式实现)和
  • 在系统中隐藏状态修改的实体之间创建定义明确的协议。

有人说,互联网是世界上最成功的基于演员的架构,实际上,这并不遥远。

于 2013-08-22T05:46:10.433 回答