Actors in Scala(Scala中的Actor)(预打印版) 第二章 Messages All the Way Up (D)

Actors in Scala(Scala中的Actor)(预打印版) 第二章 Messages All the Way Up (D)

张贵宾

guibin.beijing@gmail.com


2011.10.11


注:翻译这些英文书籍资料纯属个人爱好,如有不恰当之处敬请指正。


2.5 Asynchronous communication(异步通讯)

Actor忽略了发送消息这种事件,而着重于消息到达,这是因为在actor之间传输消息有可能发生延迟。比如actor A给actor B发送了一条消息,actor C作为持续传递的下一站。虽然C的消息是被A激活的,但是在A发送消息和C收到消息之间会有一些延迟。这些延迟可能是由于发生在B中所耗费的处理时间,或者是通信延迟。将消息延迟是完整计算中的一部分,这也是actor通讯与面向对象编程中的对象调用之间的区别。

实际当中基于actor的系统通过在actor之间异步传输消息来处理消息延迟:一旦一个actor向其他的actor派发了一个消息,发送消息的actor可以立即暂停工作,发送消息的actor不必等待响应。当然,有一些消息永远不会产生响应。如果希望得到响应,那么响应将会异步的发送出去。就像Carl Hewitt指出的,通过消息传输的actor遵循如下的规则“send it and forget it.(发送消息,然后忘掉一切)”

你也许已经从现代Web编程模型中熟悉了异步消息传输的概念,比如AJAX。AJAX是基于在Web浏览器和远程服务器之间异步消息交换的技术。由于在浏览器与服务器间的网络通信和服务器本身处理消息都存在不确定时长延时,因此AJAX的异步通信模型已经在Web应用中被证明是现实可行的。Web客户端简单的向服务器发送消息,还需要为未来处理服务器的响应注册一个监听器,然后就立即返回到UI的控制界面上保持对用户响应的交互。


相似的,在actor的通信中异步消息意味着actor模型能够在网络环境中工作的一样好,由于每一个actor都有唯一的地址。确实,Scala的actor库既定义了本地actor,也定义了远程actor。在本地actor和远程actor之间转换是令人吃惊的简单,因为异步消息在这两种情况下均能工作的非常好。除了异步消息原语,Scala actor API也为异步消息发送提供了支持。


“send it and forget it(发送消息然后就忘记消息)”的原则假设所有发出的消息最终都被目标actor收到了。虽然在许多系统中丢失消息的概念是现实存在的,比如运行目标actor的服务器可能崩溃了,结果导致目标actor永远收不到消息了,但是actor模型假设基础设施组件会保证可靠的消息传输。换句话说,actor模型假设在发送消息和传输消息之间存在有限的时间消耗。


那么如何保证消息可靠传输已经不再是基于actor的编程模型所关注的了,比方说,数据库管理系统的高可用性也不是关系代数学和SQL编程所关注的,(即关系代数学和SQL编程均假设数据库是可靠的)。Actor编程模型使得实现实现高可靠、高可用性系统变得非常简单:可靠性通常通过冗余和复制实现,actor天生就适合工作在分布式环境、并发系统中。在本书中我们将提实现可靠的actor通信的供例子和最佳实践。


2.6 You'v got email: indeterminacy and the role of the arbiter(你收到了邮件:不确定性和裁判的角色)

虽然actor模型没有规定可靠消息传输的机制,但是它承认许多消息可以紧接着发送给单独的actor。消息快速到达可能导致actor拒绝服务,表现在actor无力处理进来的消息流。为了缓解这个问题,actor模型要求每个actor提供一个特殊的对象用于接收消息,并且持有消息直到actor有能力处理这些消息。这样一种仲裁的角色我们经常称之为“邮箱”,由于它提供了类似于邮箱的功能:消息在任何时候都可以到达邮箱,并且消息一直被邮箱持有,直到接收者准备好了处理这些消息。

Email客户端给你足够的自由去选择阅读新消息的顺序,类似的,actor的邮箱也可以任何顺序为actor提供消息。由于被actor处理的消息的顺序不能提前决定——因为消息传输的顺序是不确定的——因此开发者不要依赖消息传输的顺序去确保基于actor程序的正确性。(注:但是在Scala的actor中,消息传输顺序的约束比纯粹的基于actor的编程模型要强,如果一个actor给相同的接收者发送了数条消息,那么这些消息将会以他们发出的顺序依次到达接收者的邮箱。)


Actor模型使得这样的编程实践变得非常容易,由于actor消息中可以包含任何类型的数据,并且actor能够维护自己的状态。假设,比如,有一个actor计算两个整数之和,然后把结果发送到另一个actor中。最简单的实现就是,一个单一的actor消息包含两个整数。


这种实现假设发送消息的actor同时知道这两个整数。另外一种实现则是actor可以处理来自不同发送者发送过来的整数之和,每个消息中只有一个整数。


既然加法是可交换的,那么消息传输的顺序就无关紧要了。Actor存储了收到的初始值,在此基础上收到第二个值然后计算,执行数学操作,然后发送回响应。


假设,设计了一个版本的数学actor累加一组整数,其中一种有问题的实现方式就是把每个整数消息中都包含一个lastElement的标志位,此标志用来指示是否此消息就是这一系列整数消息中的最后一个。只要这个actor一收到了标志为lastElement的整数,那就把计算结果发送给后面的流程。但是由于actor不确保消息传递的顺序,最后一个元素可能以任何顺序被收到。这样就可能导致过早的收到了错误的结果。


通过重构actor的通信机制可以减轻对消息顺序的依赖,比如重新定义消息的内容。比如在上面的例子中,消息应该除了包含lastElement标志之外,还应该包含这组整数的数量。在整个这本书中,我们会把关于不依赖消息顺序的tips及其actor的设计技术传授给大家。


在actor模型中的不确定性源于actor的邮箱或者叫仲裁者,actor的邮箱可以以任何顺序为actor提供消息。由于actor之间传输消息必然产生延时,actor模型所以不会保证消息到达的顺序,也不能指定消息到达的顺序。然而acor模型会保证消息最终一定会到达,但是消息传输的时间可能是不受控制的。


就像我们在前面章节中提到的,基于不可控的、不可预测性的编程模型的强大力量正好捕捉到了并发的本质。在actor模型中,并发是常态,而顺序计算则是特例。


2.7 Actor lifecycle(actor的生命周期)

由于actor能够敏捷的处理进入actor的消息,actor可以被想象成“活着的对象”,活着具有生命周期的对象。不象电影中的actor(演员)的生命那样生动,actor的生命比较枯燥:一旦actor被创建了,它通常就开始处理消息;一旦actor超过了起使用寿命,它就可以被停止活着销毁;或者自己自愿终止,或者通过某个特殊的“毒丸”销毁消息。


创建和启动actor是分开的,虽然创建和启动的关系非常紧密。在Scala中,actor就是普通的Scala对象,可以通过构造函数创建。在actor被启动之后,它开始处理消息,就像启动Java线程一样。


在实践中,监控actor之间的生命周期的事件非常有用,在fork-join的例子中,比如,为了释放内存,一个子actor在响应完毕父actor之后便终止。子actor可以在终止之前给父actor发送消息,告诉父actor自己终止。在Scala actor中,通过actor link功能支持对actor的生命周期监控。Actor link将在第六章6.2节中详细解释。








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值