统一了线程和事件的Actors(Actors That Unify Threads and Events)(第一节)
guibin.beijing@gmail.com
工作中使用了一年的Scala,跟着我们老大
Deng Caoyuan先生学习并做了不少分布式实时处理方面的工作,现在越来越觉得Scala中的Actor模型真是个好东西。这几天研读了Philipp Haller和Martin Odersky关于Actors设计的论文,很受启发,借此机会将论文翻译下来,与大家共勉,如果有翻译错误或者不精确的地方,敬请谅解并赐教。
本文翻译自
http://lamp.epfl.ch/~phaller/doc/haller07actorsunify.pdf,原作者 Philipp Haller 和 Martin Odersky.
摘要:在基于消息传输解决并发的方案和诸如JVM的虚拟机之间有不和谐之处,比如虚拟机经常将自己的线程同重量级的操作系统的进程对应起来。在没有轻量级的进程抽象情况下,用户经常被迫以事件驱动的方式写一些并发处理的程序,而这些基于事件驱动的程序逻辑处理使得业务流程晦涩难懂,从而增加了程序员的负担。
在这篇论文中我们展示了如何在使用了单独的Actor抽象之后将基于线程的编程模型和基于事件的编程模型统一起来。在使用了Scala编程语言中的高级抽象机制之后,我们在未修改的JVM之上实现了我们自己的线程和事件的统一。并且我们的编程模型与底层JVM的线程模型集成的非常好。
第一节. 介绍
最近并发问题由于两个趋同的趋势而受到了极大的关注:首先,多核处理器使得并发成为高效的程序执行的基础要素;其次,分布式计算和web服务本质上也是并发处理。因为基于事件的并发处理也许是一种同时解决这两种挑战的方案而颇具吸引力。这种方案被看作是线程的一种高级模型,这种模型具有将分布计算通用化的潜力。许多实际应用中的消息传递系统都是Actor模型的实例,比如Erlang编程语言就是这种并发处理机制的一种实现。Erlang支持大规模的并发处理,比如他非常轻量的实现了电话交换这种并发处理。
在像JVM这样一种主流的平台上却缺少一种相应的具有吸引力的并发实现。JVM平台上标准的并发由共享内存的线程锁机制组成,这种机制通过耗费大内存和线程切换上下文的额外开销为代价实现了并发。在这样的平台上实现的事件驱动模型,都是基于独立计算的交叉存储方式(guibin注:the interleaving of independent computations)。因此在这样的平台上以显示的事件驱动的风格编程,既复杂又容易出错,因为他涉及到了控制的倒置(guibin注:inversion of control,请参考“Why events are a bad idea (for high-concurrency servers)”,von Behren, J.R., Condit, J., Brewer, E.A.)。
在之前的文章中(guibin注:之前的文章是Event-based Programming without Inversion of Control,作者Haller, P., Odersky, M.)我们开发了基于事件的actors,这种actors能够使人们编写事件驱动的系统而不使控制倒置(guibin注:原文without inversion of control)。除了基于事件的actors的receive操作不能正常的返回到调用它的线程中之外,基于事件的actors与基于线程的actors均支持相同的其他操作,因此这种actor的完全连续性(guibin注:原文the entire continuation of such an actor)也必须是receive操作的一部分。这就使得通过连续闭包(guibin注:原文continuation closure)对挂起的actor建模成为可能,这种建模方式处理挂起的actor要远比挂起一个真正的线程要廉价的多。
在这篇论文中我将展示一个基于线程的和基于事件的acotrs的统一体。actor能够通过完全的堆栈帧被挂起(receive方式)(guibin注:原文 suspend with a full stack frame)或者通过连续闭包挂起(guibin注: 原文 suspend with just a continuation closure)(react方式)。第一种方式的挂起对应于线程的挂起,第二种方式的挂起是基于事件的编程(guibin注:挂起)。新系统合并了这两种挂起模型的优势。线程支持阻塞操作,比如像系统I/O,并且还能够在多核处理器上并行执行;基于事件的计算,另一方面,会更加的轻量级,并且能够轻易的扩展到相当大数量的actors同时执行。我们也展示了一系列的能够灵活组合这些actors的combinator。
这篇论文在几个方面改善了我们之前的工作。首先,actor是否是与线程无关一直被等到运行的时刻才被决定。一个actor也许会多次丢弃与它相对应的底层的线程栈。其次,我们之前的工作没有涉及到对两种actors的组合。之前既没有一个方案能够解决基于事件的actor的序列组合,也没有一个方法能够解决在同一个程序中对基于线程的actors和基于事件的actors的组合。
本论文中提出的方案已经在Scala的actors库中实现了。这些实现既不需要特殊的语法,也不许要编译器支持。基于函数库的实现能够根据新的需求灵活扩展的优点。事实上actors库中的实现是之前多次迭代开发的结果。然而为了方便使用,actors库利用了Scala的几个高级抽象能力,比如偏函数(guibin注:原文partial function)和模式匹配(guibin注: 原文pattern matching)。
截止目前,来自用户的经验表明,actors库在基于JVM的系统中进行并发编程要比其他技术容易的多,它简化了并发编程的复杂性,这些简化源自以下几个因素:
- 既然从设计的角度看访问一个actor的邮箱(guibin注:原文mailbox)是非竞争的,那么基于消息的并发本身要比基于内存共享的锁机制实现的并发要安全。我们相信基于模式匹配而实现的消息匹配在很多情况下会更方便。
- Actors是轻量级的。一个支持5000个并发活跃的线程的虚拟机上能够支持1,200,000个同时活跃的actors。用户因此从线程池中解放出来了。
- Actors同正常的虚拟机中的线程是完全互操作的。每一个虚拟机中的线程都被当成一个actor。这就使得actors的通信和监控能力比正常的虚拟机中的线程要高级得多。
其他人做过的解决并发问题的相关工作。Lauer 和 Needham也注意到线程和事件都具有两面性。他们建议选择任何一种方式都得基于底层的平台。在大概20年前,Ousterhout争论说使用多线程是个不好的想法,不仅因为他们经常执行的效率很糟糕,而且因为他们很难使用。最近,Behren及其他人指出,尽管事件驱动的程序比相同的基于线程的程序性能表现要好,但是它太难使用了。这主要因为两个原因:首先,程序的交互逻辑分散在多个事件处理器中(guibin注:原文event handler)(或者是分散在多个class中,比如状态设计模式),其次在各处理器中的控制流都比较晦涩,因为这些控制流都是通过操纵共享状态而实现的。在Capriccio系统中为了要达到相同的效果,它使用静态分析和编译技术来将多线程程序转换成相互协调工作的事件驱动的程序。
还有几种其他的方法可以避免上述的控制倒置问题。但是这些方法不是缺少扩展性,就是缺少对堵塞的支持, Termite Scheme将Erlang的编程模型集成进Scheme中,Scheme的第一个class continuations被开发出来用来表述进程移植(gubin注:原文 Scheme’s first-class continuations are exploited to express process migration.)然而他们的系统看起来并不支持多核处理器。而且所有已发布的该系统的测试基准都跑在单核处理器上。Responders提供了类似java扩展的一种事件循环抽象(guibin注:原文event-loop abstraction)。他们的实现是使用为每一个事件循环使用一个虚拟机线程,因此扩展性就局限在标准的JVM上了。SALSA是一种基于java的actor语言,这种语言也有相似的局限性(每一个actor都只能运行在自己的线程上)。另外消息传递的性能也因为额外开销太多而损失较大,这些损失产生是由于它将消息传递机制反射到基本的函数调用。Timber也是一种专为实时嵌入式系统而设计的面向对象的函数式语言,它提供了在可反应对象(guibin注:原文reactive objects)直接原始的同步和异步的消息通信,与我们的编程模型相比,可反应对象不可以调用可能产生不确定阻塞的操作。Frugal objects((FROBs))就是分布式的可反应对象,这些对象能够同有类型的事件交互。FROBs就是具有基于事件计算模型的一种基础actors。与Timber种的可反应对象相对应,FROBs不可以调用阻塞操作。
Li 和 Zdancewic提议了一种基于语言的方法统一事件和线程,通过把事件集成进语言级别的线程,他们获得了很可观的性能提升。然而,阻塞式的系统调用又必须被包装进非阻塞的操作中,此外如果需要给线程库添加新的事件源(比如注册事件处理器,添加事件循环等),就需要进行侵入式的改动。
actor模型已经被集成进入到不同的Smalltalk系统中,Actalk就是为Smalltalk-80而写的actor库,这个库同样也不支持多核处理器。Actra扩展了 Smalltalk/V虚拟机,并提供了重量级的处理。相反我们在未修改的虚拟机之上实现了轻量级的actors。
在第7节,我们展示了我们自己的actor实现,它能轻松扩展到是诸如SALSA所支持的纯粹基于线程的系统的两个数量级以上的actors。除此之外,我们的模型在系统中能够随着CPU核数目的增加而随之扩展,我们统一的actor模型提供了对阻塞操作的无缝支持,因此,已经存在的那些基于线程的API不用包装成非阻塞操作。不像类似Actra这样的方法,我们的实现提供了在未修改的虚拟机之上的轻量级的actor抽象。
我们的函数库受到Erlang的优雅的编程模型很大的影响。Erlang是一种动态类型的函数式编程语言,这种语言专门是为实时控制系统设计的。轻量级的被隔离的进程,使用模式匹配的异步消息传递,和控制错误传播都已经被证实是非常有效的。我们主要的贡献之一就在于将Erlang的编程模型集成进完全面向对象的函数式编程语言中。除此之外,通过将编译器的逻辑放入函数库,使得Scala语言与标准和未修改的JVM的兼容。相对于Erlang的编程模型,我们添加了组合的新形式,比如通道(guibin注:原文channel),通道提供了强类型支持和安全的交互通信。
使用continuations实现轻量级的并发处理的想法已经说了好几次了,但是现有的技术没有适合诸如JVM的虚拟机的,因为(1)访问运行时堆栈限制太严格,(2)基于堆的堆栈打破了同现有代码的互操作性。然而在Mach 3.0 kernel中实现的线程管理的方法是最后的同我们的概念相似的实现方式。当一个线程在内核中被阻塞时,它既可以保留自己的寄存器状态和堆栈以便稍后能够恢复它的状态;或者也可以保留一个指针指向continuation函数。除了函数指针,我们也可以使用闭包自动的将引用的堆栈变量移动到堆上,从而在很多情况下避免显示的状态管理。
比如关于建立快速的web服务这样一项工作(guibin注:原文There is a rich body of work on building fast web servers),是使用事件机制实现,还是使用事件和线程的结合机制(比如SEDA)来实现,已经超出了本论文讨论的范围。
我们对于基于actor的高层次的编程模型的整合,提供了强有力的不变的和轻量级的并发处理,这种使用了已经存在的现有的主流虚拟机平台的整合对于目前已知的技术来讲是唯一的方式。我们相信我们的处理方法对于在多核系统上开发并发处理的软件具有质的提升。
本章剩余部分是按照如下方式组织:下一节我们介绍我们的编程模型并且解释在目前的函数库中如何实现的。在第三节中我们介绍一个大的例子,并且这个例子在随后的章节中还会再次见到。我们的统一编程模型将在第四节中介绍。第五节介绍了作为actors通用化的通道(gubin注:原文channel)。第六节我们通过一个实例学习我们的统一编程模型如何应用在高级web应用中。一些试验性的结果在第七节中介绍,第八节是结论。
2011-03-16
Guibin
分享到:
相关推荐
本文讨论了一种方法,能够将基于线程的编程和基于事件的编程统一在一个单一的Actor抽象下。这种统一的方法可以显著减少程序员的工作负担,并提高程序的可读性和可维护性。具体来说: 1. **线程编程**:传统上,线程...
2. Actors模型是一种基于轻量级进程和消息传递的并发模型,这与传统的线程和锁模型不同,消息传递可以减少共享状态的使用,从而降低线程间同步的复杂性。 3. Scala语言对actors的支持是构建并发系统的重要工具,了解...
在Scala中,函数是第一类值,这意味着可以像操作任何其他数据类型一样操作函数。它们可以作为参数传递、作为返回值、赋值给变量,甚至存储在数据结构中。函数式编程的一些关键概念包括不可变数据、高阶函数、以及...
1. **Actor API**:Scala提供了一个简洁易用的API来创建和操作Actors。例如,通过`ActorSystem`创建一个Actor系统,然后通过`Props`创建具体的Actor实例。 ```scala import akka.actor.{Actor, ActorSystem, ...
scala-actors-2.10 jar包,可以解决 scala-actors-2.10以上版本带来的不兼容问题
- **Persistence Query:** Akka Persistence Query enables querying historical events stored by actors. This is useful for building analytics and monitoring features. - **Testing Actor Systems:** Testing...
Rational Rose是一款强大的面向对象的可视化建模工具,它支持UML(统一建模语言)以及Booch和OMT方法学。该软件可用于Windows NT、Windows 95以及多种UNIX操作系统平台。Rational Rose的核心功能在于通过图形化的...
在JavaScript的世界里,Elixir风格的Actors是一种借鉴自Elixir语言并发模型的概念,它旨在为JavaScript提供一种更安全、更可控的并发处理方式。Elixir的Actors模型基于消息传递,强调进程间的隔离和数据不可变性,这...
例如,我们可以使用`ActorSystem`来启动和管理一组Actors,通过`Props`定义Actor的行为,以及使用`ActorRef`作为Actor的引用,进行消息的发送。 在JActor 4.3.0中,重点改进了性能和稳定性。优化了内部的消息传递...
Concurrent and parallel programming have progressed from niche disciplines, of interest only to kernel programming and high-performance computing, to something that every competent programmer must ...
Reactive applications build on top of components that communicate asynchronously as they react to user and system events. As a result, they become scalable, responsive, and fault-tolerant. Java and ...
在IT行业中,"actors"通常指的是Actor模型,这是一种并发计算的理论框架,广泛应用于多线程和分布式系统设计。Actor模型是由Carl Hewitt在1973年提出的,它的核心概念是将并发实体称为“演员”(Actors),每个Actor...
HOUR 18: Making Key Input Events and Spawning Actors HOUR 19: Making an Action Encounter HOUR 20: Creating an Arcade Shooter: Input Systems and Pawns HOUR 21: Creating an Arcade Shooter: Obstacles and...
Actors in Scala 英文epub 本资源转载自网络,如有侵权,请联系上传者或csdn删除 查看此书详细信息请在美国亚马逊官网搜索此书
1. **Actor模型简介**:Actor模型是一种用于并发编程的计算模型,它将系统设计为一组独立的Actor,每个Actor都是一个具有自己状态和行为的实体。Actor之间通过消息传递进行通信,这种方式避免了共享内存所带来的复杂...
Common-Lisp-Actors, 通用Lisp的actor系统 这是一个简单且易于使用的Actor系统,在。设置需要波尔多螺纹。http://common-lisp.net/project/bordeaux-threads/ 2. 加载 actors.lisp 并开始使用它。 如果你有 Quick
Threat actors have leveraged these same benefits to evade detection and to secure their malicious activities. Traditional flow monitoring, as implemented in the Cisco® Network as a Sensor (NaaS) ...