Reactor模式

Reactor是一种事件处理的设计模式,经常用于高并发的服务端网络开发中。异步的收取消息。将不同的消息绑定到不同的回调函数上。传统的设计是一种同步的停等协议,读写操作执行后要等待当前fd的下一次可读/写事件,这期间什么都不能干,程序就阻塞在事件上。

有了Reactor以后的设计,告诉Reactor你所关注的事件和事件发生后的处理器,Reactor充当一个中间人的角色,非阻塞的检测事件是否发生,如果发生就调用注册的处理器。与传统设计不同的是Reactor可以同时非阻塞的检测多个I/O上的事件并处理,大大提高了程序运行效率。在高性能的I/O设计中,有两个比较著名的模式ReactorProactor模式,其中Reactor模式用于同步I/O,Proactor用于异步I/O操作。

Reactor 的事件处理机制

首先来回想一下普通函数调用的机制:程序调用某函数->函数执行,程序等待->函数将结果和控制权返回给程序->程序继续处理。

Reactor 释义“反应堆”,是一种事件驱动机制。和普通函数调用的不同之处在于:应用 程序不是主动的调用某个 API 完成处理,而是恰恰相反,Reactor 逆置了事件处理流程,应 用程序需要提供相应的接口并注册到 Reactor 上,如果相应的时间发生,Reactor 将主动调用 应用程序注册的接口,这些接口又称为“回调函数”。使用 Libevent 也是想 Libevent 框架注册相应的事件和回调函数;当这些时间发声时,Libevent 会调用这些回调函数处理相应的事 件(I/O 读写、定时和信号)。

Reactor模式称为反应器模式或应答者模式,是基于事件驱动的设计模式,拥有一个或多个并发输入源,有一个服务处理器和多个请求处理器,服务处理器会同步的将输入的请求事件以多路复用的方式分发给相应的请求处理器。

Reactor设计模式是一种为处理并发服务请求,并将请求提交到一个或多个服务处理程序的事件设计模式。当客户端请求抵达后,服务处理程序使用多路分配策略,由一个非阻塞的线程来接收所有请求,然后将请求派发到相关的工作线程并进行处理的过程。

在事件驱动的应用中,将一个或多个客户端的请求分离和调度给应用程序,同步有序地接收并处理多个服务请求。对于高并发系统经常会使用到Reactor模式,用来替代常用的多线程处理方式以节省系统资源并提高系统的吞吐量。

用“好莱坞原则”来形容 Reactor 再合适不过了:不要打电话给我们,我们会打电话通 知你。 举个例子:你去应聘某 xx 公司,面试结束后。 “普通函数调用机制”公司 HR 比较懒,不会记你的联系方式,那怎么办呢,你只能面 试完后自己打电话去问结果;有没有被录取啊,还是被据了;

“Reactor”公司 HR 就记下了你的联系方式,结果出来后会主动打电话通知你:有没有 被录取啊,还是被据了;你不用自己打电话去问结果,事实上也不能,你没有 HR 的留联系 方式。

Reactor 模式的优点

Reactor 模式是编写高性能网络服务器的必备技术之一,它具有如下的优点:

1)响应快,不必为单个同步时间所阻塞,虽然 Reactor 本身依然是同步的;

2)编程相对简单,可以最大程度的避免复杂的多线程及同步问题,并且避免了多线程/ 进程的切换开销;

3)可扩展性,可以方便的通过增加 Reactor 实例个数来充分利用 CPU 资源;

4)可复用性,reactor 框架本身与具体事件处理逻辑无关,具有很高的复用性。

缺点:

1) Reactor模式增加了一定的复杂性。

2) Reactor模式需要底层的同步事件多路分配器的支持。

3)Reactor模式在IO读写数据时还是在同一个线程中实现的。

Reactor 模式框架

使用 Reactor 模型,必备的几个组件:事件源、Reactor 框架、多路复用机制和事件处理 程序,先来看看 Reactor 模型的整体框架,接下来再对每个组件做逐一说明。

(1) 事件源

Linux 上是文件描述符,Windows 上就是 Socket 或者 Handle 了,这里统一称为“句柄 集”;程序在指定的句柄上注册关心的事件,比如 I/O 事件。

(2) event demultiplexer——事件多路分发机制

由操作系统提供的 I/O 多路复用机制,比如 select 和 epoll。 程序首先将其关心的句柄(事件源)及其事件注册到 event demultiplexer 上; 当有事件到达时,event demultiplexer 会发出通知“在已经注册的句柄集中,一个或多 个句柄的事件已经就绪”; 程序收到通知后,就可以在非阻塞的情况下对事件进行处理了。 对应到 libevent 中,依然是 select、poll、epoll 等,但是 libevent 使用结构体 eventop 进行了 封装,以统一的接口来支持这些 I/O 多路复用机制,达到了对外隐藏底层系统机制的目的。

(3) Reactor——反应器

Reactor,是事件管理的接口,内部使用 event demultiplexer 注册、注销事件;并运行事 件循环,当有事件进入“就绪”状态时,调用注册事件的回调函数处理事件。 对应到 libevent 中,就是 event_base 结构体。

一个典型的Reactor声明方式:

class Reactor
{
public: int register_handler(Event_Handler *pHandler, int event); int remove_handler(Event_Handler *pHandler, int event); void handle_events(timeval *ptv); // ...
};

(4) Event Handler——事件处理程序

事件处理程序提供了一组接口,每个接口对应了一种类型的事件,供 Reactor 在相应的 事件发生时调用,执行相应的事件处理。通常它会绑定一个有效的句柄。 对应到 libevent 中,就是 event 结构体。

下面是两种典型的 Event Handler 类声明方式,二者互有优缺点。


第一种:


class Event_Handler
{
public: virtual void handle_read() = 0; virtual void handle_write() = 0; virtual void handle_timeout() = 0; virtual void handle_close() = 0; virtual HANDLE get_handle() = 0; // ...
}; 

第二种:


class Event_Handler
{
public: // events maybe read/write/timeout/close .etc virtual void handle_events(int events) = 0; virtual HANDLE get_handle() = 0; // ...
}; 

Reactor 事件处理流程

前面说过 Reactor 将事件流“逆置”了,那么使用 Reactor 模式后,事件控制流是什么 样子呢? 可以参见下面的序列图。

Reactor应用场景

Reactor模式是为了应对高并发的服务器端开发。redis、netty、ZeroMQ和一些游戏服务器都采用了反应堆模式。

Reactor模式与观察者模式区别

观察者模式也称发布-订阅模式,主要是适用于对象间一对多的依赖关系,通常用作消息分发和处理,当某对象状态发生改变时,要通知其他依赖对象做出更新。是一种一对多的关系。当然,如果依赖的对象只有一个时,也是一种特殊的一对一关系。通常,观察者模式适用于消息事件处理,监听者监听到事件时通知事件处理者对事件进行处理。

而Reactor模式主要用于高效的IO模式,明显的特征是“回调”思想的运用,提高效率,避免没有必要的耗时的等待,与对象间的依赖关系无关。

两者相同点:

当一个主体发生改变时,所有依属体都得到通知。

差异点:

观察者模式与单个事件源关联,而反应器模式则与多个事件源关联 。

Reactor应用实例

libevent和libev就是比较典型的Reactor应用实例,下面以libev为例说明Reactor模式:

//初始化事件处理器
ev_io_init()//注册事件处理器,把事件处理器添加到ev_loop的观察列表中
ev_io_start()移除事件处理器,把事件处理器从ev_loop的观察列表中移除
//ev_io_stop()//reactor主循环,I/O多路复用和事件分发器
ev_run()
{//检查关注fd列表fdchanges,新增加或者修改的fd都保存在这个列表中//通过fd查找注册的事件处理器ANFD,检查事件处理器的关注事件fd_reify()//调用跨平台的多路复用api,封装过的,epoll的封装在ev_epoll.cbackend_poll()    //把事件加入待处理列表ev_feed_event()    //调用所有的待处理事件处理器ev_invoke_pending()
}

Reactor模式的主要步骤

1.client通过ev_io_init和ev_io_start接口把fd和事件处理器、套接字、关注的事件加入到reactor中;

2.Reactor的主循环调用I/O多路复用API获取就绪事件,并把就绪事件添加到就绪列表中;

3.事件分发器根据就绪列表中的fd,查找并调用client注册的事件处理器。

设计模式——Reactor模式相关推荐

  1. 设计模式--reactor 模式

    说明 本文基于 tomcat 8.5.x 编写. @author blog.jellyfishmix.com / JellyfishMIX - github LICENSE GPL-2.0 介绍 re ...

  2. 设计模式 - Reactor 模式

    https://blog.csdn.net/saienenen/article/details/111400911 1. Reactor模式简介 Netty是典型的Reactor模型结构.Reacto ...

  3. 抽丝剥茧Reactor模式

    今天在看书的时候看到了一个新的设计模式--Reactor模式,这个模式是出现在NIO中,至于这到底是个什么模式,今天我们来细说一下. 一.是什么 1.概念 reactor设计模式,是一种基于事件驱动的 ...

  4. 【IO】IO设计模式:TPR模式,Reactor模式、Proactor模式

    1.TPR模式 传统的 Server/Client 模式会基于TPR(Thread per Request),服务器会为每个客户端请求建立一个线程,由该线程单独负责处理一个客户请求. 这种模式虽然处理 ...

  5. 设计模式:高性能IO之Reactor模式

    讲到高性能IO绕不开Reactor模式,它是大多数IO相关组件如Netty.Redis在使用的IO模式,为什么需要这种模式,它是如何设计来解决高性能并发的呢? 最最原始的网络编程思路就是服务器用一个w ...

  6. swing的gui是通过何种模式进行事件响应与监听_【Vert.x准备篇2】C10K问题与Reactor模式...

    C10K问题是1999年一个叫Dan Kegel的美国人提出的概念,其中C为concurrently, 10K指的是1万个网络连接, 结合起来意为如何能够做到并发处理1万个连接. 这里首先要澄清一下, ...

  7. 两种高性能I/O设计模式(Reactor/Proactor)的比较

    综述 这篇文章探讨并比较两种用于TCP服务器的高性能设计模式. 除了介绍现有的解决方案,还提出了一种更具伸缩性,只需要维护一份代码并且跨平台的解决方案(含代码示例),以及其在不同平台上的微调. 此文还 ...

  8. 两种高性能 I/O 设计模式 Reactor 和 Proactor

    Reactor 和 Proactor 是基于事件驱动,在网络编程中经常用到两种设计模式. 曾经在一个项目中用到了网络库 libevent,也学习了一段时间,其内部实现所用到的就是 Reactor,所知 ...

  9. 高性能I/O设计模式Reactor和Proactor

    昨天购买了<程序员>杂志 2007.4期,第一时间去翻阅了一遍,其中有一篇<两种高性能I/O设计模式的比较>令人眼睛一亮,这是一篇译文,偶最近在一直想认真看看这方面的文章很久了 ...

最新文章

  1. Coding之路——重新学习C++(2):static的详细理解
  2. 史上最详细微信小程序授权登录与后端SprIngBoot交互操作说明,附源代码,有疑惑大家可以直接留言,蟹蟹 2021.11.29完善更新小程序代码,
  3. 构造函数及其参数列表初始化问题
  4. 创业一定要做自己“喜欢”并且有“优势”的事情
  5. 微软BI SSIS 2012 辅助阅读博客
  6. APUE 头文件apue.h 解决方法
  7. 深度学习模型加速方法
  8. 计算机游戏教学法PPT,幼儿园语言游戏教学法PPT课件
  9. 学习记录514@react使用antd选择器设置下拉菜单宽度
  10. 十月美剧精听总结 - 权力的游戏「Game of Throne」 黑袍纠察队「The boys」 老无所依「No Country for the old men」
  11. python调用foxmail 发邮件_foxmail 收取已发送邮件
  12. 计算机维修情况说明书,电脑坏了(电脑坏了情况说明)
  13. 基于SSM框架的杰森摄影工作室选片系统的设计和开发论文
  14. 18、基于STM32的自动浇花系统
  15. 刚发布!新型病毒下,程序员可在家免费学习了!
  16. 统计学习方法 | 概论
  17. vue cli3及4版本的全局引入scss
  18. 心理学|颜色是如何影响我们的情绪的?
  19. 【keil5】keil5仿真STM32设置
  20. 湘潭大学通信原理期末简答题

热门文章

  1. Stable Diffusion教学 使用Lora制作AI网红 【AI绘画真人教程】
  2. mysql 表级锁 和元数据锁(MDL)
  3. route虚拟服务器模拟,Windows Server 2012R2 路由和网桥设置
  4. HyperWorks二次开发API-孔的识别
  5. 电脑内存怎么看?只需1分钟,快速查看
  6. DELMIA软件弧焊仿真:以两零件相交线为焊缝生成机器人焊点坐标
  7. 手机充电器的参数解释
  8. 青铜10:千锤百炼-如何解决生产者与消费者经典问题
  9. 解读FixMatch: Simplifying Semi-Supervised Learning with Consistency and Confidence
  10. java fst 入门 例子_Redis 使用 fst 进行序列化