我对演员模型的描述正确吗?


13

据我了解,参与者模型就像对象模型一样,但是有一些区别:

  1. 每个对象都产生它自己的单独线程,即使有成千上万个对象,也不是问题。
  2. 参与者不是通过调用函数和获取返回值来进行交互,而是通过发送和接收消息来进行交互。
  3. 如果您不违反该模型,则您的应用将充分利用并发功能,而不会出现竞争状况的风险。
  4. 在OO中可以执行的所有操作都可以使用actor来完成,但更好的是,问题在于最近几年我们编写的所有内容都是基于OO的-但即将进行过渡。

因此,举例来说,假设我必须定义3d向量类/角色,创建两个实例,并对它们调用求和运算。

面向对象:

class V3d {
   constructor V3d(x,y,z) //bla
   float x,y,z;
   function sum(V3d b) 
   { 
      return V3d(x+b.x,y+b.y,z+b.z); 
   }
}

//using:
mySum = V3d(1,2,3).sum(V3d(3,2,1)) //creates 2 instances, sum, returns instantly
drawPoint(mySum) //uses the result

演员模型:

actor V3d 
{
    constructor V3d(x,y,z) //bla
    float x,y,z;
    loop 
    {
       receive 'sum',b:V3d :
           send(caller,'sumResult',V3d(x+b.x,y+b.y,z+b.z))
    }
 }

//using:
send(V3d(1,2,3),'sum',V3d(3,2,1)) //creates 2 instances, send to the first one a request to sum with the second one

loop 
{
   receive 'sumResult',result:
      drawPoint(result) //receives result and draws it
}

是吗 还是我完全错了?


轻量级参与者或微代理或数据流组件不一定使用其自己的线程。:-)检查以下术语:基于角色的编程,基于代理的编程,基于数据流的编程。它们非常相似,但是有不同的约束。哦,我会问这个问题;-)
inf3rno

Answers:


12

简短的答案是不,这是不正确的。

  1. 启动合理正确(每个Actor至少有可能作为独立线程执行),但随后又大步偏离轨道。该模型没有什么可以使许多线程正常工作的,这取决于实现。至多,创建大量线程的简便性给实现有效的线程化带来了压力。至少就模型而言,演员与对象之间的任何相似之处大多是偶然的。“对象”包含有关如何组合代码和数据的相当具体的含义。参与者通常会同时涉及代码和数据,但是对它们如何组合几乎没有什么暗示(除了外界唯一可见的数据是消息这一事实)。

  2. 描述交互的通常方式是消息发送,是的。我没有引用方便,但是很久以前有人证明了C ++虚拟函数之类的机制对于消息发送是同构的(因为虚拟函数通常是实现的,所以您在vtable中使用了偏移量-但是如果您而是将偏移量发送到消息表中,效果会相同)。

  3. 这不是那么简单。如果可以找到副本,Henry Baker(和我现在不记得的其他人)写了一篇关于Actor模型中数据一致性所必需的规则的论文。

  4. “更好”充其量是非常主观的。有些问题本质上是高度并行的,实际上确实涉及大量的基本自治的实体,而交互作用最少,而这些交互主要是异步的。在这种情况下,参与者模型确实可以很好地工作。对于其他问题,实际上并非如此。本质上,一些问题几乎完全是串行的。其他指令可以并行执行,但是仍然需要这些动作之间的紧密同步(例如,本质上类似于SIMD的模式,您一次执行一条指令,但是每条指令都作用于大量数据项)。使用actor模型当然可以解决这两种类型的问题-但是对于此类问题,通常涉及大量额外工作,而获得的收益很少或没有。


参与者数量和线程数量之间没有关系;actor模型保证的是,给定实例一次只能由一个线程操作,因此actor已经是线程安全的,并且您不需要在其中使用同步和锁定策略。
罗布·克劳福德

@RobCrawford:这是确保Actor模型中数据一致性的一种(非常简单的)方法。休伊特/贝克的论文涵盖了更多的可能性,例如在单独的线程中运行的Actor的多个副本(嗯...看我的回答,我想知道我是真的记不起当时的卡尔•休伊特的名字了吗?讽刺的是我写的时候)。
杰里·科芬

消息传递的异步性不是模型的基本要素吗?这肯定会阻止它与虚拟函数调用同构,虚拟函数调用本质上是同步的。还是从某种角度讲,区别是不相关的?
博西

2

关于1:我曾经使用过单线程Actor建模的应用程序,因此完全有可能忽略此建议的大线程数。AFAIK,线程无论如何都不是轻量级的对象,因此可能不希望每个actor都有一个,这取决于您使用的actor数量。

关于3:我很确定,仅由于编程逻辑,竞争条件就可以在演员模型系统中发生吗?

关于4:定义“更好”?我的经验是,异步逻辑比同步逻辑要难读得多。例如,在上面的示例中,您不知道哪个操作负责哪个结果,因此需要进行额外的消息跟踪。一旦将其添加进来,并且其他消息进出都包含在逻辑中,则代码的意图将散布在多个发送/接收函数中。

综上所述,我非常喜欢将actor模型用于应用程序的高层。因为添加依赖项比添加函数要困难一点,所以它可以使去耦更加容易。我也没有比Java语言更高级的经验,其他范式可能以更基本的方式支持异步性。


关于#1:嗯,“线程”可以指很多东西。OS线程通常是相当重量级的,但确实如此,但是有些语言运行时在内部处理少数OS线程中成百上千的执行“线程”。在某些实现中,此类模型显然可以扩展到数十个内核(我已经看到最近的GHC版本可以与32个内核配合使用的陈述)。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.