演员模型

在電腦科學中,演員模型英語:)是一種並行運算上的模型。「演員」是一種程式上的抽象概念,被視為並行運算的基本單元:當一個演員接收到一則訊息,它可以做出一些決策、建立更多的演員、傳送更多的訊息、決定要如何回答接下來的訊息。演员可以修改它们自己的私有状态,但是只能通过消息间接的相互影响(避免了基于锁的同步)。

演員模型在1973年於Carl Hewitt、Peter Bishop及Richard Steiger的論文中提出[1]。它已经被用作并发计算理论理解框架和并发系统实际实现基础。演员模型和其他类似工作的关系讨论可见于演员模型和进程演算

基本概念

演员模型推崇的哲学是“一切皆是演员”,这与面向对象编程的“一切皆是对象”类似。

演员是一个运算实体,响应接收到的消息,相互间是并发的:

  • 发送有限数量的消息给其他演员;
  • 创建有限数量的新演员;
  • 指定接收到下一个消息时要用到的行为。

以上动作不含有顺序执行的假设,因此可以并行进行。

发送者与已发送通信的解耦,是演员模型的根本优势,演员模型启用了异步通信并将控制结构当作消息传递的模式[2]

消息接收者是通过地址区分的,有时也被称作“邮件地址”。因此演员只能和它拥有地址的演员通信。它可以通过接收到的信息获取地址,或者获取它创建的演员的地址。

演员模型的特征是,演员内部或相互之间的计算本质上是并发性的,演员可以动态创建,演员地址包含在消息中,交互只有通过直接的异步消息传递通信,不限制消息到达的顺序。

历史

演员模型受到了编程语言LispSimula、早期版本的Smalltalk基于权力的系统分组交换的影响。它的发展是“由几十、几百、甚至几千独立的微处理机构成的高度并行计算机器的前景所推动的,每个处理机都有自己局部内存和通信处理器,通过高性能网络进行通信。”[3]从那时起,随着通过多核众核计算机架构的大规模并发的到来,人们已经复兴了对演员模型的兴趣。

跟从Hewitt、Bishop和Steiger在1973年的出版物,Irene Greif为演员模型开发了一个操作语义作为他的博士论文研究的一部份[4]。两年以后,Henry Baker和Hewitt出版了针对演员系统的一组公理法则[5][6]。其他的主要里程碑包括William Clinger的1981年学位论文,介入了基于Power domains指称语义[3],和Gul Agha的1985年学位论文,它进一步的发展了基于transition的语义模型,补充了Clinger的模型[7]。这些工作导致了演员模型理论的全面发展。

主要的软件实现工作是麻省理工学院(MIT)消息传递语义小组的Russ Atkinson、Giuseppe Attardi、Henry Baker、Gerry Barber、Peter Bishop、Peter de Jong、Ken Kahn、Henry Lieberman、Carl Manning、Tom Reinhardt、Richard Steiger和Dan Theriault完成的。分别由加州理工学院(Caltech)的Chuck Seitz和MIT的Bill Dally领导的研究组,致力于构造进一步发展在这个模型中的消息传递的计算机架构。参见演员模型实现

关于演员模型的研究已经在加州理工学院京都大学微电子及计算机技术公司(MCC), MIT人工智能实验室、SRI斯坦福大学伊利诺伊大学厄巴纳-香槟分校[8]皮埃尔和玛丽·居里大学(巴黎第六大学)、比萨大学东京大学米澤研究室、荷兰数学和计算机科学研究学会(CWI)和其他一些地方开展了。

影响

演员模型在理论发展和实践软件开发中都有影响。

理论

演员模型影响了π-演算和后续的进程演算的发展。在Robin Milner的图灵奖获奖演讲中,他写到[9]

现在,纯粹的lambda演算只使用两种东西来建造:项(term)和变量。我们在进程演算上能实现如此的经济节约吗?Carl Hewitt,与他的演员模型一起,很久以前就响应了这个挑战;他宣布值、在值上的算子(operator)和进程都应该是同一种东西:演员。

这个目标打动了我,因为它意味着表达式的同质性和完整性 ... 但是很久以前我就能领会到如何依据代数演算来达成这个目标 ...

所以,本着Hewitt的精神,我们的第一步是,要求由项指示的或由名字访问的所有东西,值、寄存器、算子、进程、对象,都是同一种东西;它们都应当是进程。

实践

演员模型在商业实践中已经有了巨大的影响。例如,Twitter将演员用于可伸缩性应用[10]。还有,Microsoft在开发的异步代理库中使用了演员模型[11]。下面章节列出了很多其他的演员库。

使用演员模型编程

一些编程语言使用了演员模型或变种。这些语言包括:

早期演员模型编程语言

后期演员模型编程语言

演员模型库及框架

演员模型库及框架,允许用户在没有内置演员模型的语言中进行编程。这些框架包括:

名称 状态 最新发行 许可证 语言
Acteur 活跃 2020-04-16[29] Apache-2.0 / MIT Rust
Bastion 活跃 2020-08-12[30] Apache-2.0 / MIT Rust
Actix 活跃 2019-05-30[31] MIT Rust
Aojet 活跃 2016-10-17 MIT Swift
Actor 活跃 2017-03-09 MIT Java
Actor4j 活跃 2020-01-31 Apache 2.0 Java
Actr 活跃 2019-04-09[32] Apache 2.0 Java
Vert.x 活跃 2018-02-13 Apache 2.0 Java, Groovy, Javascript, Ruby, Scala, Kotlin, Ceylon
ActorFx 不活跃 2013-11-13 Apache 2.0 .NET
Akka 活跃 2019-05-21[33] Apache 2.0 Java and Scala
Akka.NET 活跃 2020-08-20[34] Apache 2.0 .NET
Remact.Net 不活跃 2016-06-26 MIT .NET, Javascript
Ateji PX 不活跃 ? ? Java
czmq 活跃 2016-11-10 MPL-2 C
F# MailboxProcessor 活跃 same as F# (built-in core library) Apache License F#
Korus 活跃 2010-02-04 GPL 3 Java
Kilim[35] 活跃 2018-11-09[36] MIT Java
ActorFoundry (based on Kilim) 不活跃 2008-12-28 ? Java
ActorKit 活跃 2011-09-13[37] BSD Objective-C
Cloud Haskell 活跃 2015-06-17[38] BSD Haskell
CloudI 活跃 2018-12-19[39] MIT C/C++, Elixir/Erlang/LFE, Go, Haskell, Java, Javascript, OCaml, Perl, PHP, Python, Ruby
Clutter 活跃 2017-05-12[40] LGPL 2.1 C, C++ (cluttermm), Python (pyclutter), Perl (perl-Clutter)
NAct 不活跃 2012-02-28 LGPL 3.0 .NET
Nact 活跃 2018-06-06[41] Apache 2.0 JavaScript/ReasonML
Retlang 不活跃 2011-05-18[42] New BSD .NET
JActor 不活跃 2013-01-22 LGPL Java
Jetlang 活跃 2013-05-30[43] New BSD Java
Haskell-Actor 活跃? 2008 New BSD Haskell
GPars 活跃 2014-05-09[44] Apache 2.0 Groovy
OOSMOS 活跃 2019-05-09[45] GPL 2.0和商业(双许可证) C. C++ friendly
Panini 活跃 2014-05-22 MPL 1.1 自己的编程语言
PARLEY 活跃? 2007-22-07 GPL 2.1 Python
Peernetic 活跃 2007-06-29 LGPL 3.0 Java
PostSharp 活跃 2014-09-24 商业 / Freemium .NET
Pulsar 活跃 2016-07-09[46] New BSD Python
Pulsar 活跃 2016-02-18[47] LGPL/Eclipse Clojure
Pykka 活跃 2019-05-07[48] Apache 2.0 Python
Termite Scheme 活跃? 2009-05-21 LGPL Scheme (Gambit实现)
Theron 不活跃[49] 2014-01-18[50] MIT[51] C++
Thespian 活跃 2020-03-10 MIT Python
Quasar 活跃 2018-11-02[52] LGPL/Eclipse Java
Libactor 活跃? 2009 GPL 2.0 C
Actor-CPP 活跃 2012-03-10[53] GPL 2.0 C++
S4 不活跃 2012-07-31[54] Apache 2.0 Java
C++ Actor Framework (CAF) 活跃 2020-02-08[55] Boost Software License 1.0 and BSD 3-Clause C++11
Celluloid 活跃 2018-12-20[56] MIT Ruby
LabVIEW Actor Framework 活跃 2012-03-01[57] National Instruments SLA LabVIEW
LabVIEW Messenger Library 活跃 2016-06-01 BSD LabVIEW
Orbit 活跃 2019-05-28[58] New BSD Java
QP frameworks for real-time embedded systems 活跃 2019-05-25[59] GPL 2.0和商业(双许可证) C and C++
libprocess 活跃 2013-06-19 Apache 2.0 C++
SObjectizer 活跃 2020-05-09[60] New BSD C++11
rotor 活跃 2020-10-23[61] MIT License C++17
Orleans 活跃 2019-06-02[62] MIT License C#/.NET
Skynet 活跃 2016-07-11 MIT License C/Lua
Reactors.IO 活跃 2016-06-14 BSD License Java/Scala
libagents 活跃 2020-03-08 Free software license C++11
protoactor 活跃 2018-09-22 Free software license Go, C#, Python, JavaScript, Java, Kotlin
FunctionalJava 活跃 2018-08-18[63] BSD 3-Clause Java
Riker 活跃 2019-01-04 MIT License Rust
Comedy 活跃 2019-03-09 EPL 1.0 JavaScript
vlingo 活跃 2020-07-26 Mozilla Public License 2.0 Java, Kotlin, soon .NET
waSCC 活跃 2020-08-30 Apache 2.0 WebAssembly (Rust, TinyGo, Zig, AssemblyScript)
ray 活跃 2020-08-27 Apache 2.0 Python

注意这里没有列出全部框架和库。

并发编程语言用例

尽管设计者并未如此表述[64]Erlang语言一般被引证为采用演员模型的典型代表之一。在Erlang中,进程间通信是通过无共享异步消息传递系统运作的:所有进程都有一个自己的“邮箱”,它是从其他进程已经发送过来而仍未被消费的消息的队列。进程使用receive原语来检索匹配预期模式的消息。一个消息处理例程针对每个模式依次测试这些消息,直到其中有一个匹配。在消息被消费并从邮箱中移除之时进程恢复执行。消息可以包含任何Erlang结构,包括原始类型(整数,浮点数、字符、原子)、元组、列表和函数。

下面例子展示了Erlang对分布式进程的内建支持:

 % 建立一个进程并启用函数web:start_server(Port, MaxConnections)
 ServerProcess = spawn(web, start_server, [Port, MaxConnections]),

 % 建立一个远程进程并启用函数
 % web:start_server(Port, MaxConnections)于机器RemoteNode
 RemoteProcess = spawn(RemoteNode, web, start_server, [Port, MaxConnections]),

 % 发送消息到ServerProcess(异步的)。消息包含一个元组
 % 它具有原子"pause"和数"10"。
 ServerProcess ! {pause, 10},

 % 接收发给这个进程的消息
 receive
         a_message -> do_something;
         {data, DataContent} -> handle(DataContent);
         {hello, Text} -> io:format("Got hello message: ~s", [Text]);
         {goodbye, Text} -> io:format("Got goodbye message: ~s", [Text])
 end.

原型的演员编程语言

Hewitt在2006年发表了一个原型的演员编程语言,用意在于直接表达演员行为的重要方面[65]。消息采用如下表示法:

<标签>[<元素>1 ... <元素>n]

编程语言的语义是通过将每个程序构造确定为有自己行为的演员来定义的。执行是通过在执行期间让Eval消息在程序构造之间传递来建模的。

环境演员

每个Eval消息都有一个充当环境的演员的地址,它能够进行标识符与值的绑定(binding)。environment演员是不可变的(immutable),也就是不变更的。当一个environment演员收到Request[Bind[identifier value] customer]的时候,建立一个新的环境演员environment’发送给customer,使得这个新环境演员收到Request[Lookup[identifier’] customer’]的时候,如果identifier同于identifier’,则发送给customer’一个Returned[value],否则发送给environment一个Request[Lookup[identifier’] customer’]

当一个environment演员收到Request[Bind[<模式> String] customer]的时候,如果此<模式>形如Request[msg[paramerer] customer],匹配于String形如Request[msg[argument] customer],则建立一个新的环境演员environment’发送给customer,使得这个新环境演员收到Request[Lookup[parameter’] customer’]的时候,如果parameter’同于parameter,则发送给customer’一个Returned[argument],否则发送给customer一个Thrown[NotFound[<模式>]]

当一个environment演员收到Request[Bind[identifier(parameter) value] customer]的时候,建立一个新的环境演员environment’发送给customer,使得这个新环境演员收到Request[Lookup[identifier’(argument)] customer’]的时候,如果identifier同于identifier’,则建立一个新的环境演员environment’’,发送给customer’一个Returned[value]和一个Returned[environment’’],否则发送给environment一个Request[Lookup[identifier’(argument)] customer’]。这个新环境演员environment’’在收到Request[Lookup[parameter’] customer’]的时候,如果parameter’同于parameter,则发送给customer’一个Returned[argument],否则发送给environment’一个Request[Lookup[parameter’] customer’]

上述环境演员建造在EmptyEnvironment演员之上,它在接收到Request[Lookup[identifier] customer]的时候,发送给customer一个Thrown[NotFound[identifier]]。当它收到Bind请求的时候,EmptyEnvironment表现的如同上述环境演员。

表达式

原型语言有如下种类的表达式,这里的通信包括Request[...]Returned[...]Thrown[...],这里的消息包括Eval[...]Bind[...]Lookup[...]

<标识符>
在收到Request[Eval[environment] customer]的时候,发送给environment一个Request[Lookup[<标识符>] customer]
send <接收者> <通信>
在收到Request[Eval[environment] customer]的时候,建立一个新演员evalCustomer1,发送给<接收者>一个Request[Eval[environment] evalCustomer1],使得
evalCustomer1收到通信Returned[theRecipient]的时候,建立一个新演员evalCustomer2,发送给<通信>一个Request[Eval[environment] evalCustomer2],使得
evalCustomer2收到通信Returned[theCommunication]的时候,发送给theRecipient一个theCommunication
<接收者>.<消息>
在收到Request[Eval[environment] customer]的时候,建立一个新演员evalCustomer1,发送<接收者>一个Request[Eval[environment] evalCustomer1],使得
evalCustomer1收到通信Returned[theRecipient]的时候,建立一个新演员evalCustomer2,发送给<消息>一个Request[Eval[environment] evalCustomer2],使得
evalCustomer2收到通信Returned[theMessage]的时候,发送给theRecipient一个Request[theMessage customer]
receiver ... <模式>i <表达式>i ...
在收到Request[Eval[environment] customer]的时候,发送给customer一个新演员theReceiver,使得
theReceiver收到通信内容com的时候,建立一个新演员bindingCustomer,并发送给environment一个Request[Bind[<模式>i com] bindingCustomer],而且
  1. 如果bindingCustomer收到Returned[environment’],发送给<表达式>i一个Request[Eval[environment’]]
  2. 不然如果bindingCustomer收到Thrown[...],尝试<模式>i+1
behavior ... <模式>i <表达式>i ...
在收到Request[Eval[environment] customer]的时候,发送给customer一个新演员theReceiver,使得
theReceiver收到Request[message customer’]的时候,建立一个新演员bindingCustomer,并发送给environment一个Request[bind[<模式>i message] customer’],而且
  1. 如果bindingCustomer收到Returned[environment’],发送给<表达式>i一个Request[Eval[environment’] customer’]
  2. 不然如果bindingCustomer收到Thrown[...],尝试<模式>i+1
{<表达式>1, <表达式>2}
在收到Request[Eval[environment] customer]的时候,发送给<表达式>1一个Request[Eval[environment]],而且并发的发送给<表达式>2一个Request[Eval[environment] customer]
let <标识符> = <表达式> in <表达式>
在收到message[Eval[environment] customer]的时候,建立一个新演员evalCustomer,并发送给<表达式>一个Request[Eval[environment] evalCustomer]
evalCustomer收到Returned[theValue]的时候,建立一个新演员bindingCustomer,并发送给environment一个Request[bind[<标识符> theValue] bindingCustomer]
bindingCustomer收到Returned[environment’]的时候,发送给<expression>一个Request[Eval[environment’] customer]
serializer <表达式>
在收到Request[Eval[environment] customer]的时候,发送给customer一个Returned[theSerializer],这里的theSerializer是新演员,使得发送到theSerializer的通信按FIFO次序由行为演员处理,行为演员初始是<表达式>.Eval[environment],而且
theSerializer收到通信内容com的时候,建立一个新演员customer’,发送给行为演员一个Request[com customer’],使得
customer’收到Returned[value]Returned[theNextBehavior]的时候,Returned[value]被发送给customer,而theNextBehaviortheSerializer用作下次通信的行为演员。

例子程序

下面是简单的存储单元格(cell)的例子脚本(script),它可以包含任何演员地址:

Cell ≡
receiver
Request[Create[initial] customer]
send customer Returned[serializer ReadWrite(initial)]

上述脚本将建立一个存储单元格,它采用的行为ReadWrite定义如下:

ReadWrite(contents) ≡
behavior
Request[read[] customer]
{send customer Returned[contents], Returned[ReadWrite(contents)]}
Request[write[x] customer]
{send customer Returned[], Returned[ReadWrite(x)]}

例如,下列表达式建立一个单元格x,具有初始内容5,并接着并发的向它写值7和9。

let x = Cell.Create[5] in {x.write[7], x.write[9], x.read[]}

上述表达式的值是5、7或9。

参见

引用

  1. Carl Hewitt; Peter Bishop and Richard Steiger. (PDF). IJCAI. 1973.
  2. Carl Hewitt. Viewing Control Structures as Patterns of Passing Messages. Journal of Artificial Intelligence. June 1977.
  3. William Clinger. . Mathematics Doctoral Dissertation. MIT. June 1981. hdl:1721.1/6935.
  4. Irene Greif. . EECS Doctoral Dissertation. MIT. August 1975.
  5. Henry Baker; Carl Hewitt. . IFIP. August 1977.
  6. (PDF). 10 May 1977.
  7. Gul Agha. . Doctoral Dissertation. MIT Press. 1986. hdl:1721.1/6952.
  8. . Osl.cs.uiuc.edu. [2012-12-02]. (原始内容存档于2013-02-22).
  9. Milner, Robin. . Communications of the ACM. 1993, 36: 78–89. doi:10.1145/151233.151240.
  10. . Waimingmok.wordpress.com. 2009-06-27 [2012-12-02].
  11. "Actor-Based Programming with the Asynchronous Agents Library" MSDN September 2010.
  12. Henry Lieberman. . MIT AI memo 625. June 1981.
  13. Henry Lieberman. . MIT AI memo 626. June 1981.
  14. Jean-Pierre Briot. Acttalk: A framework for object-oriented concurrent programming-design and experience 2nd France-Japan workshop. 1999.
  15. Ken Kahn. A Computational Theory of Animation MIT EECS Doctoral Dissertation. August 1979.
  16. William Athas and Nanette Boden Cantor: An Actor Programming System for Scientific Computing in Proceedings of the NSF Workshop on Object-Based Concurrent Programming. 1988. Special Issue of SIGPLAN Notices.
  17. Darrell Woelk. Developing InfoSleuth Agents Using Rosette: An Actor Based Language Proceedings of the CIKM '95 Workshop on Intelligent Information Agents. 1995.
  18. Dedecker J., Van Cutsem T., Mostinckx S., D'Hondt T., De Meuter W. Ambient-oriented Programming in AmbientTalk. In “Proceedings of the 20th European Conference on Object-Oriented Programming (ECOOP), Dave Thomas (Ed.), Lecture Notes in Computer Science Vol. 4067, pp. 230-254, Springer-Verlag.”, 2006
  19. Darryl K. Taft. . Eweek.com. 2009-04-17 [2012-12-02].
  20. Brandauer, Stephan; 等. . Formal Methods for Multicore Programming. (Springer International Publishing). 2015: 1–56.
  21. . Dalnefre.com. [2012-12-02].
  22. .
  23. Clebsch, Sylvan; Drossopoulou, Sophia; Blessing, Sebastian; McNeil, Andy. . . 2015: 1–12. ISBN 9781450339018. doi:10.1145/2824815.2824816. by Sylvan Clebsch, Sophia Drossopoulou, Sebastian Blessing, Andy McNeil
  24. . 2019-03-08.
  25. . 2019-03-12.
  26. Carlos Varela and Gul Agha. . ACM SIGPLAN Notices. OOPSLA'2001 Intriguing Technology Track Proceedings. 2001, 36.
  27. Philipp Haller and Martin Odersky. (PDF). Proc. JMLC 2006. September 2006.
  28. Philipp Haller and Martin Odersky. (PDF). Technical report LAMP 2007. January 2007 [2014-08-04]. (原始内容 (PDF)存档于2011-06-07).
  29. . crates.io. [2020-04-16].
  30. Bulut, Mahmut. . Crates.io. 2019-12-15 [2019-12-15].
  31. . crates.io. [2019-06-03].
  32. . Github.com. [2019-04-16].
  33. . Akka. 2019-05-21 [2019-06-03].
  34. Akka.NET v1.4.10 Stable Release , Akka.NET, 2020-10-01 [2020-10-01]
  35. Srinivasan, Sriram; Alan Mycroft. (PDF). . Cyprus. 2008 [2016-02-25].
  36. . Github.com. [2019-06-03].
  37. . Github.com. [2016-02-25].
  38. . Github.com. [2012-12-02].
  39. . Github.com. [2019-06-03].
  40. . gitlab.gnome.org. [2019-06-03].
  41. . [2019-06-03].
  42. . [2016-02-25].
  43. . 2012-02-14 [2016-02-25].
  44. . GitHub. [2016-02-25].
  45. . GitHub. [2019-06-03].
  46. . (原始内容存档于2015-07-04).
  47. . (原始内容存档于2013-07-26).
  48. . pykka.org. [2019-06-03].
  49. . [2018-08-29].
  50. . Theron-library.com. [2016-02-25]. (原始内容存档于2016-03-16).
  51. . Theron-library.com. [2016-02-25]. (原始内容存档于2016-03-04).
  52. . [2019-06-03].
  53. . [2012-12-02].
  54. . apache.org. [2016-01-16]. (原始内容存档于2016-03-06).
  55. . Github.com. [2020-03-07].
  56. . RubyGems.org. [2019-06-03].
  57. . Decibel.ni.com. 2011-09-23 [2016-02-25].
  58. . GitHub. [2019-06-03].
  59. . Sourceforge.net. [2019-06-03].
  60. . GitHub. [2019-06-19].
  61. . GitHub. [2020-10-10].
  62. . GitHub. [2019-06-03].
  63. . GitHub. [2018-08-23].
  64. Armstrong, Joe. . Communications of the ACM. September 2010, 53 (9): 68–75. doi:10.1145/1810891.1810910. Erlang is conceptually similar to the occam programming language, though it recasts the ideas of CSP in a functional framework and uses asynchronous message passing instead of the synchronous message passing in CSP.
  65. Carl Hewitt. The repeated demise of logic programming and why it will be reincarnated. What Went Wrong and Why: Lessons from AI Research and Applications. Technical Report SS-06-08. AAAI Press. March 2006.

延伸阅读

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.