统一了线程和事件的Actors(Actors That Unify Threads and Events)(第二节)
guibin.beijing@gmail.com
本文翻译自
http://lamp.epfl.ch/~phaller/doc/haller07actorsunify.pdf,原作者 Philipp Haller 和 Martin Odersky.
第二节. 使用Actors编程
Actor是一个能通过消息传递的方式与其他actor通信的进程。总共有两种主要的通信抽象,分别叫做“send”和“receive”。表达式 a ! msg 表示把消息msg发送到actor a上。Send是一种异步操作,比如这个操作执行完毕后会立即返回。消息会在actor的邮箱中缓冲着。receive操作有如下的形式:
引用
receive {
case msgpat1 => action1
...
case msgpatN => actionN
}
匹配了模式
msgpati的第一个消息从邮箱中被清除掉,与此同时
actioni被执行,如果没有匹配上任何一个模式,那么这个actor就被挂起。
代码 1:
Fig. 1. Example: orders and cancellations 写道
// base version
val orderMngr = actor {
while (true)
receive {
case Order(sender, item) =>
val o =
handleOrder(sender, item)
sender ! Ack(o)
case Cancel(sender, o) =>
if (o.pending) {
cancelOrder(o)
sender ! Ack(o)
} else sender ! NoAck
case x => junk += x
}
}
val customer = actor {
orderMngr ! Order(self, myItem)
receive {
case Ack(o) => ...
}
// version with reply and !?
val orderMngr = actor {
while (true)
receive {
case Order(item) =>
val o =
handleOrder(sender, item)
reply(Ack(o))
case Cancel(o) =>
if (o.pending) {
cancelOrder(o)
reply(Ack(o))
} else reply(NoAck)
case x => junk += x
}
}
val customer = actor {
orderMngr !? Order(myItem) match {
case Ack(o) => ...
}
}
比如代码1中的示例代码,表达式
actor { body } 创建了一个新的actor,这个actor能够运行
body中的代码。表达式
self用来引用当前在执行的actor。每一个java线程也叫做一个actor,因此即便是主线程也能执行
receive。
代码1中的例子展示了目前介绍的actor的所有用法。首先,我们定义一个actor
orderMngr在内部的一个无限循环中接受消息。
receive操作一直在等待两种类型的消息。
Order(sender, item)处理器处理
item的一个订单。当订单(Order)的对象创建时,同时也创建了发送订单的actor的引用,并且当订单对象处理完毕后,确认信息送还给发送者。
Cancel(sender, o)表示如果订单o还处于等待状态的话就取消订单,取消完毕后向发送者发送确认信息。如果订单不是处于等待状态,则向发送者发送NoAck消息,表示要求取消的是非等待订单。
在
orderMngr的
receive中的最后的模式是一个可变模式,这个模式可以匹配任何消息。可变模式从邮箱中删除无法匹配上的没用的消息(“junk”)。我们有定义了一个customer actor,这个actor在发送了一个订单消息,在继续向下执行之前等待来自
orderMngr的确认消息。既然使用
actor方法生成的actor是异步的,因此我们定义的actors都是可以并行运行的。
注意,在上面的实例代码中我们做了许多重复性的工作用来实现请求/应答风格的通信。尤其是
sender被显示的包含在了每一条消息中。这样的使用方式经常出现,因此我们的库函数对这种使用方式给予特殊的支持,即消息经常携带sender的信息,可以使用下面的语法:
引用
a !? msg 向a发送msg消息,等到响应之后返回。
sender 用来引用发送了最近一条被self接受了的消息的actor
reply(msg) 将消息回复给sender
a forward msg 使用当前的sender将消息发送给a,而不是使用self
使用了这些附加的便利工具,第一个例子就可以被重写成第二个例子。
看看上面展示的例子,可以看出Scala语言似乎是专门为actor的并发而设计的。事实上不是这样的,Scala仅仅假定了底层主机的基本线程模型。在例子中展示的所有上层的操作都是在Scala库中的class及class的方法定义的。在余下的章节中,我们将打开盖子看看下面是如何组成和实现的。并发处理的实现将在第四节中讨论。
发送消息的操作 ! 是用于给actor发送一条消息的。语法 a ! msg 是方法调用 a.!(msg) 的简写形式,就像 x + y 在Scala中是 x.+(y) 的简写一样。因此我们在Actor trait中定义了 ! 方法。
引用
trait Actor {
private val mailbox = new Queue[Any]
def !(msg: Any): unit = ...
...
}
这个方法做了两件事情,首先将从参数传入的消息入队进入Actor的邮箱中,这个邮箱现在是用一个私有的 Queue[Any] 类型的成员表示。其次,如果此时receiving actor在
receive语句中处于挂起的状态,那么此时actor的执行语句就被触发,其中这个receive语句是能够处理发送过来的消息的。
receive { ... }结构很有意思,在Scala中,在花括号中的模式匹配表达式被当作第一类对象,这个对象能想receive方法传入参数,并且传入参数的类型是
PartialFunction,这个PartialFunction是Function1的子类,Function1是一元函数相对应的基类。这两个方法的定义如下:
引用
abstract class Function1[-a,+b] {
def apply(x: a): b
}
abstract class PartialFunction[-a,+b] extends Function1[a,b] {
def isDefinedAt(x: a): boolean
}
Functions就是具有
apply方法的object,而partial functions是除了有
apply方法之外,还有一个附加的
isDefinedAt(x: A)方法的object,这个
isDefinedAt方法是用来测试是否定义了相应给定了参数的函数(guibin注:即检查参数x是否在该PartialFunction函数的作用域中)。这两种类型的class都是(类型)参数化的(gubin注:原文parameterized);首先,第一个类型参数
a表示函数的输入参数类型,第二个类型参数
b表示该函数的结果类型。
模式匹配表达式:
引用
{case p=> e; ...; case p=> e}
因此是一个定义了如下方法的partial function:
- 如果其中一个模式Pi匹配上了参数,则isDefinedAt方法返回true,否则返回false。
- 如果第一匹配上了输入参数的模式Pi,则apply方法返回相应的值ei。如果没有任何一个模式能够匹配上输入参数,则会抛出MatchError异常来。
这两个方法在receive中的实现如下。首先,在邮箱中的消息按照其出现的顺序被扫描,如果某个消息的定义正好是receive的输入参数
f(guibin注:第一点,receive的实际定义是def receive[R](f: PartialFunction[Any, R]): R = {......},即receive的输入参数是PartialFunction类型的,第二点,如果扫描到的邮箱中的消息正好在PartialFunction中有定义,且匹配上了这个PartialFunction中定义的某个模式),则这条消息从邮箱中被删除,并且f被应用到这个消息上(guibin注:也就是说针对这个消息调用receive中f对应的相应的执行操作),另外一方面,如果对邮箱中的每条消息调用 f.isDefinedAt(m) 都返回 false,则这个receiving actor被挂起。
actor和
self均是定义在
Actor object中的方法。Object特点在于在运行时情况下,确保只有一个实例,跟java中的static 方法类似。比如:
引用
object Actor {
def self: Actor ...
def actor(body: => unit): Actor ...
...
}
注意,Scala对类型和术语(types and terms)有不同的命名空间。比如,
Actor这个名字既用于上面的object的名字(这里是术语,term),也用于trait的名字(trait Actor),即self和actor方法的返回类型的名字(这里是类型,type)。在
actor方法的定义中,参数
body定义了新生成的actor的行为。这是一个返回类型为unit的闭包(guibin注:原文closure),开始的箭头
=> 表示这是一个还未被求值计算的表达式(thunk,形实转换程序)。
在Scala的actor库中,还有其他的函数我们没有涉及到,比如有一个方法
receiveWithin这个方法能够指定一个时间段,在此时间段内消息应该能被收到,如果超过该时间段仍然没有收到,则允许actor 超时。当超时时,与
TIMEOUT模式相匹配的行为将会被触发。超时能够用来挂起一个actor,完全清除邮箱中的消息,或者实现有优先级的消息。
Guibin
2011-03-19
分享到:
相关推荐
本文讨论了一种方法,能够将基于线程的编程和基于事件的编程统一在一个单一的Actor抽象下。这种统一的方法可以显著减少程序员的工作负担,并提高程序的可读性和可维护性。具体来说: 1. **线程编程**:传统上,线程...
2. Actors模型是一种基于轻量级进程和消息传递的并发模型,这与传统的线程和锁模型不同,消息传递可以减少共享状态的使用,从而降低线程间同步的复杂性。 3. Scala语言对actors的支持是构建并发系统的重要工具,了解...
在JVM平台上,利用Scala中的Actors可以更简单地实现并发程序,因为Actors模型能够自然地管理并发和同步问题,而无需直接操作线程和锁。 Actors是并发模型中的一个基本构造,它们以轻量级的方式在用户空间实现,提供...
#### 二、Actors模型的特点 1. **轻量级对象**:Actors是轻量级的对象,每个Actor都独立于其他Actor运行,它们之间通过发送消息进行通信。 2. **异步消息传递**:Actors之间的通信是基于异步消息传递机制实现的,这...
2. **Fault Tolerance:** Akka provides robust mechanisms for handling failures and ensuring that critical services remain available. Actors can be designed to recover automatically from failures, ...
scala-actors-2.10 jar包,可以解决 scala-actors-2.10以上版本带来的不兼容问题
Rational Rose是一款强大的面向对象的可视化建模工具,它支持UML(统一建模语言)以及Booch和OMT方法学。该软件可用于Windows NT、Windows 95以及多种UNIX操作系统平台。Rational Rose的核心功能在于通过图形化的...
5. **并发控制**:尽管JavaScript的单线程特性限制了并行执行,但我们可以利用事件循环和异步操作(如Promise、async/await)来模拟并发。通过将任务分解为小块,让它们在事件队列中顺序执行,可以提高程序的执行...
2. **Actor生命周期**:了解如何创建、启动、停止Actor,以及如何处理Actor的故障和重启。 3. **Actor上下文**:掌握`ActorContext`对象,它是Actor内部操作的入口,可以用来创建子Actor、发送消息、获取...
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删除 查看此书详细信息请在美国亚马逊官网搜索此书
2. **Scala与Actor模型**:Scala是一种功能强大且灵活的多范式编程语言,它支持函数式、面向对象和并发编程风格。在Scala中,Actor模型的实现非常优雅和高效,主要得益于其内置的Actor库(如Akka)。通过Scala的...
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) ...