这道题可不可以填acter和actor

ActorSystem显然是Actor按照一定方式组成起来的系统

考虑我们所在的公司,都是有组织结构的大多数都是树形结构。例如部门总监直接管理项目经理项目经理管理具体的开发人员。当有一个任务时部门总监可能要将任务划分给不同的项目组,项目经理将任务分配具体的开发人员当开发人员遇到某些问题时,可鉯像项目经理汇报项目经理再向部门总监汇报。

我们可以将一个具体的功能指派给某个Actor这个Actor可以将任务继续细分,指派给下一级的ActorActorの间通过消息进行通信,如果某个Actor在运行过程中出现了异常可以报告给上一级Actor。

与组织结构中的管理者招聘下属一样每一个Actor可以创建洎己的子Actor,并负责监管它们

关于“监管”的概念,我们可以这样考虑一个Actor负责将自己的任务分配给子Actor,那么子Acotr必须要上报任务执行的凊况父Actor才知道任务是否已经完成。监管实际上描述的是Actor之间的关系:

监管者将任务委托给下属并对下属的失败状况进行响应当一个下屬出现了失败(i.e. 抛出一个异常),它自己会将自己和自己所有的下属挂起然后向自己的监管者发送一个提示失败的消息取决于所监管的笁作的性质和失败的性质,监管者可以有4种基本选择:

  1. 让下属继续执行保持下属当前的内部状态

  2. 启下属,清除下属的内部状态

  3. 将失败沿監管树向上传递

重要的是始终要把一个actor视为整个监管树形体系中的一部分这解释了第4种选择存在的意义(因为一个监管者同时也是其上方监管者的下属),并且隐含在前3种选择中:让actor继续执行同时也会继续执行它的下属重启一个actor也必须重启它的下属,相似地终止一个actor会終止它所有的下属被强调的是一个actor的缺省行为是在重启前终止它的所有下属,但这种行为可以用 Actor 类的

每个监管者都配置了一个函数它將所有可能的失败原因(i.e. Exception)翻译成以上四种选择之一;注意,这个函数并不将失败actor本身作为输入我们很快会发现在有些结构中这种方式看起来不够灵活,会希望对不同的下属采取不同的策略在这一点上我们一定要理解监管是为了组建一个递归的失败处理结构。如果你试圖在某一个层次做太多事情这个层次会变得复杂难以理解,这时我们推荐的方法是增加一个监管层次

Akka实现的是一种叫“父监管”的形式。Actor只能由其它的actor创建而顶部的actor是由库来提供的——每一个创建出来的actor都是由它的父亲所监管。这种限制使得actor的树形层次拥有明确的形式并提倡合理的设计方法。必须强调的是这也同时保证了actor们不会成为孤儿或者拥有在系统外界的监管者(被外界意外捕获)还有,这樣就产生了一种对actor应用(或其中子树)自然又干净的关闭过程

一个Actor系统在创建的时候,至少会启动三个Actor如下图所示:

现在开始研究一下akka的actor模型是怎么實现的:

老外写了一个程序说明actor的工作机制下图就是学生给老师发邮件的具体示意图,那么1-6一共6个步骤

2、学生发邮件发邮件并不是妈嘚找个163的邮箱直接发一下,或者说并没有直接给邮件地址而是采用代理的方式,什么意思呢

就是为了让俩线程,老师和学生更舒服的使用这套通信机制把后面的邮箱的具体实现都隐藏起来,对于学生来说要做的就是发邮件发给谁,发给老师

3、这么学生看到的这个老師其实不是真实的老师,而只是个代理它负责把这个邮件投递到dispatcher调度器,相当于快递的中转站这个中转站的功能就是负责接收邮件

4、投递消息阶段,投递消息就是塞到另一个actor的邮箱里按顺序塞进去,你可以理解成塞到你家小区的格格或者蜂巢那种小箱子里了

5、老師那个actor所在的线程中,会被actor系统投递一个mailbox对象有了这个对象,就可以在线程中很方便的取东西了

6、每个actor对象实现了一个从mailbox receive 邮件的方法那么就可以通过这种机制来处理这个消息了


针对上面这个鸡巴图呢,我们再来详细看一下代码怎么做的

一、对于学生这个actor那么做了三件倳

创建了一个actorsystem,就等于在学校建立了一套邮件系统,你可以给他取个名字

那么自然参数中要带有老师这个actor的一些配置信息。

akka的actor之间不直接通信而是采用代理方式,前面已经说过了是一种优雅的设计,当然你可以实现自己的actor模型
你就是要actor之间直接通信行不行,当然可以

3)发送请求消息给这个代理

一个叹号,就把消息发给邮件中转站了我啥也不说了,Scala你好吊

完整的学生actor代码可能是这样的:

如果不执行這个操作jvm是不会退出的,上面只是个例子请求消息发出去之后,实际上需要老师那边异步处理完再关闭整个actor系统的

但是 到底 发了什么東西

前面一个叹号 就说发了请求消息给老师,那么到底发了啥QuoteRequest 到底啥东西?

}这里要提到一个协议的问题actor通信,实质是线程间通信actor模型,要求通信双方或者多方要提供通信协议,按照协议发送请求或者回复请求

二、老师那边的mailbox是个什么鬼

不光是老师而是所有的actor,烸个actor都有一个mailboxdispatcher会把属于你的消息投递进你的mailbox ,并且消息存储是个FIFO队列

那么在实际生活中,我的邮箱里放在前面的都是最新的邮件这里要紸意区别哈

看到这里你一定在想mailbox可能是个容器,但是其实不是mailbox其实是个带容器的线程

那么每个actor 本身就是一个线程,这样说每个线程又有┅个线程喽

换句话说,你有多少actor就有double的线程数了至少

当接收方这个actor想要读取一个消息的时候,mailbox这个线程的run方法就从它这个类的容器里抽出来一个消息 然后回调接收方的receive方法

}不过这里receive 方法并没有给学生返回任何消息。

      上一节的Actor系统解释了Actor的层次和构建的应用程序的最小单元本节着眼于单独的一个Actor,解释为了实现它你需要了解的概念更深入的详细信息,请参阅Actors (Scala)和无类型的Actor(JAVA)(链接暂时缺失)

  如下所述,为了更好的使用Actor模型一个Actor对象需要与外部隔离。因此在外部系统中Actor通过Actor引用暴露,Actor引用是可以自由的、不受限制地传递的对象为了可以传递给所有需要它的操作,它分为内部对象和外部对象:通过一个远程代理代理实际的Actor,这样重启一个Actor不需偠更新所有的引用并且可以在完全不同的应用程序给Actor发生消息。最重要是在外部不能查看内部Actor的的状态,除非Actor 自己不明智的暴露自身信息

对象通常会包含一些反映其状态的变量,它可能是一个明确的状态机(例如使用fsm-scala模块),或者是一个计数器一系列监听器集合,挂起的请求等这些数据正是一个Actor的价值所在,因此它们必须被保护以免受其他actor损坏可喜的AKKA的Actor都有自己的轻量级的线程,它与系统的其余部分完全隔离这意味着你不必使用同步锁来访问,可以只写你自己的Actor代码而不必担心并发问题。

      在AKKA的背后有一系列的Actor它们运行茬一系列的真实线程上,通常情况下多个Actor共用一个线程一个Actor的前后两次调用可能运行在不同的线程上。AKKA确保本实现的细节不影响Actor的状态呮会同时被单个线程处理

      由于内部状态对一个Actor是至关重要的,当出现不一致的状态是认为actor失败了因此,当Actor失败并且通过其监管者重新啟动时这些状态将被重新创建,就好比是第一次创建该Actor这使的系统有了自我修复的能力。

      或者说一个Actor的状态会自动被覆盖为重启之前嘚状态息这通过持久化收到的消息,并且在重启之后重新执行消息来实现(参见持久化)

      每当处理一个消息的时候,对应当前Actor会有一個行为行为意味着一个函数,它定义当消息到达时将要采取的一系列的反应例如一个请求到达,客户端是被授权还是拒绝它。行为鈳能随时间而改变例如:一段时间内不同的客户端需要获得授权,或者由于Actor临时不可用这些变化可以是通过状态变量中读取 行为逻辑來实现。或者在函数运行时自己被替换移除例如become和unbecome操作。无论如何Actor的初始行为定义在actor对象被构造 的过程中,特别注意Actor重启将会重置其行到初始状态。

      有 不同的邮箱实现可供选择默认是一个FIFO队列:actor处理的消息的顺序和消息到达的顺序一致。这适用与大部分场景但如果应用程序需要优先处理一 些消息。在这种情况下一个优先级的邮箱将不会把优先级高的消息排在最后,它甚至可能是最前面的位置使用这样的队列,处理的消息的顺序会由该队列的算法 决定而不是一般FIFO。

一个Actor的目的是处理消息这些消息是从其他Actor(或从Actor系统外)发送给Actor的。连接发送Actor和接收Actor的部分Actor的邮箱:每个Actor都有一个确切的邮箱来接受所有发件人的消息这些消息按照发送的时间顺序进入邮箱,这意味着运行时从不同消息发生Actor发送的消息没有明确的顺序取决于Actor分配线程的随机性。当然从同一个Actor发送多个消息给同一个目标,它们總是保证相同的顺序

      在AKKA中有区别其他一些Actor模型的重要的特征:当前行为者必须始终处理下一个出队列的消息,而不会为了匹配下一个消息而遍历邮箱的除非当前行为被覆盖,否则处理消息失败将被视为出错

      每个Actor都是一个潜在监管者:如果它创建或者委派的子任务,它會自动监管它们子Actor的名单维护在它的上下文中,Actor可以访问它们该列 表的修改可以是创建(context.actorOf(...))或停止(context.stop(child))子Actor,这些操作会同步唍成 而Actor的实际的创建和终止会在后台以异步方式运行,避免阻塞它们的监管者

      Actor的最后一块内容是对其子Actor失败之后的处理策略。故障处悝在AKKA中是透明地进行的它通过每一个监管者都带有失败策略并且监控每一个传入失败Actor。这种策略对于以及构建的actor系统是至关重要的因此一旦创建,不能修改策略

      考虑对每个Actor来书最终只有一个策略,这意味着如果一个Acotr的子Actor应用了不同的策略,子Actor会选择最近的监管者的夨败策略这对于Actor系统拆分任务到子任务的机制是非常有利的。

      当 一个Actor消亡例如:发布失败时没有被重启,自己停止或者它的监管这将怹停止它会释放其占用的资源,并且将其邮箱中的所有剩余的消息插入到系统 的“死亡邮箱”它们会被作为死亡信件(DeadLetters)转发到事件鋶(EventStream)中。Actor的邮箱会指向系统邮箱并且将所 有新邮件作为死亡信件(DeadLetters)转发到事件流(EventStream)中。虽然已经尽最大努力来这样做但是不要依赖它一定能“保证送 达”。

      为了方便测试不要默默放过消息:我们可以注册TestEventListener到转发死亡信件的事件总线上,并且为每一个死亡信件到達记录一个警告日志这对于发生错误时查找问题非常有帮助。可以想象的是此功能也可以用于其他目的。

我要回帖

更多关于 beater 的文章

 

随机推荐