zoukankan      html  css  js  c++  java
  • [面试]Actor模型

    Actor模型

    面试中自己说话不利落, 或者自己对知识点认识不全面.在这里进行一下记录. 理论部分都是收集(copy)自网上其他的博客.

    什么是Actor模型

    参与者模式英语:Actor model)是一种并发运算上的模型。

    “参与者”是一种抽象概念,被视为并发运算的基本单元:当一个参与者接收到一则消息,它可以做出一些决策、创建更多的参与者、发送更多的消息、决定要如何回答接下来的消息。Actor模型的理念非常简单:天下万物皆为Actor。

    在使用Java进行并发编程时需要特别的关注锁和内存原子性等一系列线程问题,而Actor模型内部的状态由它自己维护即它内部数据只能由它自己修改(通过消息传递来进行状态修改). 

    Actor模型的组成是什么

            1.状态(state):Actor中的状态指的是Actor对象的变量信息,状态由Actor自己管理,避免了并发环境下的锁和内存原子性等问题

            2.行为(Behavior):行为指定的是Actor中计算逻辑,通过Actor接收到消息来改变Actor的状态

            3.邮箱(mailBox):邮箱是Actor和Actor之间的通信桥梁,邮箱内部通过FIFO消息队列来存储发送方Actor消息,接受方Actor从邮箱队列中获取消息. 

    为什么同一个功能的Actor会有多个实例

    尽管许多actors同时运行,但是一个actor只能顺序地处理消息。也就是说其它actors发送了三条消息给一个actor,这个actor只能一次处理一条。所以如果你要并行处理3条消息,你需要把这条消息发给3个actors。

    消息异步地传送到actor,所以当actor正在处理消息时,新来的消息应该存储到别的地方。Mailbox就是这些消息存储的地方。

    Actor做什么

    当一个actor接收到消息后,它能做如下三件事中的一件:

             1. Create more actors; 创建其他actors

             2. Send messages to other actors; 向其他actors发送消息

             3. Designates what to do with the next message. 指定下一条消息到来的行为

    一个actor能维持一个私有状态。「指定下一条消息来到做什么」意味着可以定义下条消息来到时的状态。

    设想有一个actor像计算器,它的初始状态是数字0。当这个actor接收到add(1)消息时,它并不改变它原本的状态,而是指定当它接收到下一个消息时,状态会变为1。

    Actor模型的优点

            1. 事件模型驱动--Actor之间的通信是异步的,即使Actor在发送消息后也无需阻塞或者等待就能够处理其他事情

            2. 强隔离性--Actor中的方法不能由外部直接调用,所有的一切都通过消息传递进行的,从而避免了Actor之间的数据共享,想要观察到另一个Actor的状态变化只能通过消息传递进行询问. 

            3. 位置透明--无论Actor地址是在本地还是在远程机上对于代码来说都是一样的

            4. 轻量性--Actor是非常轻量的计算元,只需少量内存就能达到高并发

            5. 如果不用actor模型, 随着项目体量增大,业务愈加复杂,不可避免大量使用“锁”,然而“锁”的其实是很耗性能的,所以大量使用锁的机制肯定会造成效率不高. 即使大量依赖“锁”解决了系统中资源竞争的情况,但是由于没有一个规范的编程模式,最后系统的稳定性肯定会出问题,最根本的原因是没把系统的任务调度抽象出来,由于任务调度和业务逻辑的耦合在一起,很难做一个很高层的抽象,保证任务调度有序。

            6.作为开发者我们只需要关心每个Actor的逻辑就可以了,避免“锁”的“滥用”

    Actor缺点

    当所有逻辑都跑在Actor中时,很难掌控Actor的粒度,稍有不慎就可能造成系统中Actor个数爆炸的情况,Actor当出现必须共享数据或者状态时就很难避免使用“锁”,但似乎由于上面的“Actor可能会堵塞自己,但Actor不应该堵塞它运行的线程”准则冲突,这个时候也许可以选择使用redis做数据共享.

    Actor模型的调度方式

    Actor模型有两种任务调度方式:

            1. 基于线程的调度:为每个Actor分配一个线程,在接收一个消息时,如果当前Actor的邮箱(mail box)为空,则会阻塞当前线程。基于线程的调度实现较为简单,但线程数量受到操作的限制,现在的Actor模型一般不采用这种方式;

            2. 基于事件的调度:事件可以理解为上述任务或消息的到来,而此时才会为Actor的任务分配线程并执行。

    基于线程的调度为每个Actor分配一个线程,在接受一个消息(如在Scala Actor中使用receive)时,如果当前Actor的“邮箱(mail box)”为空,则会阻塞当前线程直到获得消息为止。基于线程的调度实现起来较为简单. 但是线程数量一多就会影响到系统资源占用以及调度,而在某些情况下大部分的Actor会处于空闲状态,而大量阻塞线程既是系统的负担,也是资源的浪费。因此现有的Actor Model大都不会采取这种方式。

    基于事件的调度中, “事件”在这里可以简单理解为“消息到达”事件,而此时才会为Actor的任务分配线程并执行, 既保证了运算资源的充分占用,也不会让系统在同时进行的太多任务中“疲惫不堪”,这样系统便可以得到很好的伸缩性。在Scala Actor中也可以选择使用“react”而不是“recive”方法来使用基于事件的方式来执行任务。

    Actor的容错(Fault tolerance)

    Erlang 引入了「随它崩溃」的哲学理念,这部分关键代码被监控着,监控者的唯一职责是知道代码崩溃后干什么(如将这个单元代码重置为正常状态),让这种理念成为可能的正是actor模型。

    每段代码都运行在process中,process是erlang称呼actor的方式。这个process完全独立,意味着它的状态不会影响其他process。我们有个supervisor,实际上它只是另一个process(所有东西都是actor),当被监控的process挂了,supervisor这个process会被通知并对此进行处理。这就让我们能创建「自愈」系统了。如果一个actor到达异常状态并崩溃,无论如何,supervisor都可以做出反应并尝试把它变成一致状态,这里有很多策略,最常见的是根据初始状态重启actor。

    Actor与分布式的关系

    关于actor模型的有趣方面是它并不在意消息发送到的actor是本地的或者是另外节点上的。

    转念一想,如果actor只是一些代码,包含了一个mailbox和一个内部状态,actor只对消息做出响应,谁会关注它运行在哪个机器上呢?只要我们能让消息到达就行了。这允许我们基于许多计算机上构建系统,并且恢复其中任何一台。

    用WordCount举例

    比如现在要在3台物理节点上运行一个WordCount作业,可以将这个作业细分为Split、Count和Merge三种任务(任务的target是物理节点的地址,communication可能包含文本、单词及计数等),根据需求要有Split Actor、Count Actor和Merge Actor。整个作业的处理流程以下:

            1. Split Actor接收到消息后可以文本分割成10份,每份发送给一个Count Actor;

            2. Count Actor统计好单词的数目后发送消息给Merge Actor;

            3. Merge Actor收集完Count Actor发送的10个消息后,合并每个单词的数目,完成WordCount任务。

    从以上例子可以看出,Actor系统跟数据驱动系统比如数据流相近,可以自定义任务的流向及其处理过程。

    参考博客(就是copy+整理):

    https://blog.csdn.net/gulianchao/article/details/7249117

     https://www.cnblogs.com/lixiang-share/p/5829437.html

  • 相关阅读:
    Java内存泄漏的排查总结
    多文本匹配 AC算法(Aho-Corasick)
    Linux下进程管理利器—supervise(监控并将死掉的程序重启)
    maven pom项目的dependencies转gradle格式
    Protocol Buffers官方文档(开发指南)
    Spring的工具类StringUtils使用
    springboot2 中Druid和ibatis(baomidou) 遇到org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.iflytek.pandaai.service.multi.mapper.TanancyMapper
    gradle 多模块Springboot项目 compile project引用其他模块的坑
    JAVA 运行springboot jar包设置classpath
    mysql8
  • 原文地址:https://www.cnblogs.com/noKing/p/9187362.html
Copyright © 2011-2022 走看看