并发IO模型 Proactor

Proactor:

 

  Proactor将所有I/O操作都交给主线程和内核来处理,工作线程仅仅负责业务逻辑。使用异步I/O模型(aio_read和aio_write)来实现Proactor模式的工作流程是:

1、主线程调用aio_read向内核注册socket上的读完成事件,并告诉内核用户缓冲区的位置,以及读操作完成时如何通知应用程序(可以用信号)
主线程继续处理其他逻辑
2、当socket上的读数据被读入用户缓冲区后,内核向应用进程发送一个信号,已通知应用程序数据已经可用
3、应用进程预先定义好的信号处理函数选择一个工作线程来处理处理客户请求,工作线程处理完客户请求之后,调用aio_write向内核注册socket的完成写事件,并告诉内核用户写缓冲区的位置,以及操作完成时如何通知应用程序(可以用信号)
4、主线程继续处理其他逻辑
5、当用户缓冲区的数据被写入socket之后,内核将向应用程序发送一个信号,已通知应用程序数据已经发送完毕
应用程序预先定义好的信号处理函数选择一个工作线程来做善后处理,比如决定是否关闭socket

 

Reactor:

 

  要求主线程(I/O处理单元)只负责监听文件描述符上是否有事件发生,有的话就立即将事件通知工作线程(逻辑单元)数据的读写,接受新的连接以及处理客户请求均在工作线程中完成;除此之外,逻辑线程不作任何工作。

1、主线程往epoll内核事件表中注册socket上的读就绪事件
2、主线程调用epoll_wait等待socket上有数据可读
3、当socket上有数据可读时,epoll_wait通知主线程,主线程则将socket可读事件放入请求队列。
4、睡眠在请求队列上的某个工作线程被唤醒,它从socket读取数据,并处理客户请求,然后往epoll内核事件表中注册该socket上的写就绪事件。
5、主线程调用epoll_wait等待socket可写
6、当socket可写时,epoll_wait通知主线程,主线程将socket可写事件放入请求队列
7、睡眠在请求队列上的某个工作线程(工作线程从请求队列读取事件后,根据事件的类型来决定如何处理它,没有必要区分读工作线程和写工作线程)被唤醒,它往socket上写入服务器处理客户请求的结果

 

actor:

 


    * 无锁:每个Actor在同一时间处理最多一个消息,可以发送消息给其他Actor,保证了单独写原则。从而巧妙避免了多线程写争夺。
    * 异步:Actor之间通信方式是异步的,这是Actor实现异步的基础。每个Actor都有一个MailBox用来接受消息,Actor按照接受消息的顺序,逐条处理。
这样的设计主要优势就是解耦了Actor,数万个Actor并发的运行,每个actor都以自己的步调运行,且发送消息,接收消息都不会被阻塞。
    * 隔离:Actor模型内部的状态由它自己维护,即它内部数据只能由它自己修改(通过消息传递来进行状态修改)。不同Actor处于物理隔离状态。
    * 位置透明:由于Actor模型基于消息传递方式,每个Actor实例的位置透明,无论Actor地址是在本地还是在远程机器上对于代码来说都是一样的。
    * 容错:传统编程是防御式编程,在可能出错的地方加异常处理。Actor模型遵循:任其崩溃哲学理念,让Actor的管理者去处理这些崩溃问题。每个Actor的崩溃或者异常都反馈到管理者处,由管理者决定处理方式。

状态(state):Actor中的状态指的是Actor对象的变量信息,状态由Actor自己管理,避免了并发环境下的锁和内存原子性等问题
行为(Behavior):行为指定的是Actor中计算逻辑,通过Actor接收到消息来改变Actor的状态
邮箱(mailBox):邮箱是Actor和Actor之间的通信桥梁,邮箱内部通过FIFO消息队列来存储发送方Actor消息,接受方Actor从邮箱队列中获取消息
 

例如: 
        将计数器场景中基于线程的实现替换为Actor,当然Actor也要在线程中运行,但Actor只在有事情可做(没有消息要处理)的时候才会使用线程。
        在计数器场景中,请求者代表CutomerActor,计数器数量由TicketsActor来维护并持有当前计数器的状态。CustomerActor和TicketsActor在空闲idle或没有事情做的时候都不会持有线程。
在初始购买操作时CustomerActor需要发送一个消息给TicketsActor,消息中包含了要购买的数量。当TicketsActor接收到消息时会校验购买数量是否超过库存数量,若合法则递减数量。此时TicketsActor会发送一条消息给CutomerActor表明订单被成功接受。若购买数量超过库存数量TicketsActor也会发送给CustomerActor一条消息,表明订单被拒绝。
         可划分两个阶段的行为检查和递减操作,也可以通过同步操作序列来完成。但是基于Actor的实现不仅在每个Actor中提供了自然的操作同步,还能避免大量的线程积压,防止线程等待轮到它们执行同步代码区域。明显会降低系统资源的占用。
          Actor模型本身确保处理是按照同步的方式执行的。TicketsActor会处理其收件箱中的每条消息,注意这里没有复杂的线程或锁,只是一个多线程的处理过程,但Actor系统会管理线程的使用和分配

          基于以上的介绍,Actor模型在设计层面天生就支持了负载均衡,而且对于水平扩容支持的非常好。当然Actor的分布式系统也是需要服务注册中心的。

    1. 每个Actor的mailBox有可能会出现堆积或者满的情况,当这种情况发生,新消息的处理方式是被抛弃还是等待呢,所以当设计一个Actor系统的时候mailBox的设计需要注意。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值