如何设计和构造使用Actors的程序

时间:2013-08-21 17:44:15

标签: ruby concurrency erlang actor celluloid

Joe Armstrong's dissertation开始,他指出应该按照以下三个步骤设计一个基于Actor的程序。问题是,我不明白这些步骤如何映射到现实世界的问题或如何应用它们。这是Joe的原始建议。

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

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

我认为#1很容易搞清楚。这是我迷路的#2(和3)。为了说明我的挫折感,我在这个要点(Ruby service with callbacks)中找到了一个小服务。

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

  1. 开始
  2. LoginGateway
  3. LogoutGateway
  4. 停止
  5. 订阅
  6. 根据服务所处的状态,其中一些服务不起作用(或不起作用)。如果服务尚未启动,则登录/注销/订阅没有意义。这种状态信息与Joe的3个步骤有关吗?

    无论如何,考虑到该gist中的示例/模拟服务,我想知道有人会如何设计一个以Actory方式包装此服务的程序。我想看一下如何应用Joe的3个步骤的指南列表。写一些代码(任何语言)的加分点。

1 个答案:

答案 0 :(得分:9)

通常,在构建应用程序以使用actor时,您必须识别应用程序的并发功能,这可能很棘手。您确定了5个并发“服务”:

  1. 开始
  2. LoginGateway
  3. LogoutGateway
  4. 停止
  5. 订阅
  6. 1,4和5似乎是可以流经系统的消息类型,2和3我不确定如何描述。你的要点相当大,对我来说不是 super ,但看起来你有一些消息队列系统。 用户可以采取的操作是:

    1. 登录系统
    2. 退出系统
    3. 订阅消息的队列
    4. 我假设登录和退出需要一些身份验证步骤。我将进一步假设,如果用户未通过身份验证步骤,则他们的连接会中断,但创建连接的身份验证不足。

      系统采取的措施是:

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

        如果这不是广泛的,请告诉我,我会改变这个答案。 (我假设发送给用户的消息不是由用户生成,但是系统的固有部分;也许我们正在讨论监控服务。 )无论如何,这里并发什么?一些事情:

        1. 用户彼此独立行事
        2. 队列具有单独的状态
        3. 基于actor的体系结构将每个并发实体表示为其自己的进程。 用户是一个有限状态机,可以对队列进行身份验证,订阅,或者接收消息并订阅更多队列并最终断开连接。在Erlang / OTP中,我们用gen_fsm表示。 用户进程包含与客户端交互所需的所有状态,如果我们通过网络公开服务,则该进程将是套接字。

          身份验证意味着系统本身就是一个“进程”,但很可能它实际上是一个集合进程,在Erlang / OTP中我们称之为{ {3}}。我离题了。为简化起见,我们假设系统本身就是一个单一进程,它具有一些定义良好的协议和保持用户凭据的状态。 用户登录是一条明确定义的消息,从 用户进程 系统< / strong>过程及其响应。如果没有身份验证,我们就不需要系统进程,因为与用户相关的唯一状态是套接字。

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

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

          (在Erlang / OTP中,我们的用户主管确保进程保持活动并在死机时重新启动,这极大地简化了Erlang开发人员为确保基于actor的架构的可靠性而必须完成的工作量。)< / p>

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

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

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