随着IO多路复用技术的出现,出现了很多事件处理模式。同步I/O模型通常由Reactor模式实现,而异步I/O模型则由Proactor模式实现。

  • Reactor模式:

  Reator类图如上所示,Reactor模式又叫反应器或反应堆,即实现注册描述符(Handle)及事件的处理器(EventHandler),当有事件发生的时候,事件多路分发器(Event Demultiplexer)做出反应,调用事件具体的处理函数(ConcreteEventHandler::handle_event())。

  Reator模式的典型启动过程如下:

  1. 创建Reactor
  2. 注册事件处理器(Reactor::register_handler())
  3. 调用事件多路分发器进入无限事件循环(Reacor:handle_events)
  4. 当操作系统通知某描述符状态就绪时,事件多路分发器找出并调用此描述符注册的事件处理器。

   Reactor模式已经被广泛使用,著名的开源事件库libevent、libev、libuv都是使用Reactor模式。

  Reactor模式的优点:

  • 实现相对简单,对于耗时短的处理场景处理高效;
  • 操作系统可以在多个事件源上等待,并且避免了多线程编程相关的性能开销和编程复杂性;
  • 事件的串行化对应用是透明的,可以顺序的同步执行而不需要加锁;
  • 事务分离:将与应用无关的多路分解和分配机制和与应用相关的回调函数分离开来。

  Reactor模式的缺点:

  Reactor处理耗时长的操作(如文件I/O)会造成事件分发的阻塞,影响到后续事件的处理。

  因此涉及到文件I/O相关的操作,需要使用异步I/O,即使用Proactor模式效果更佳。

  • Proactor模式

  Proactor模式的类图如上图所示,Proactor模式又叫前摄器或主动器模式。它用于实现异步I/O模型,运行流程如下:

  1. Initiator主动调用Asynchronous Operation Processor发起异步I/O操作,

  2. 记录异步操作的参数和函数地址放入完成事件队列(Completion Event Queue)中

  3. Proactor循环检测异步事件是否完成。如果完成则从完成事件队列中取出回调函数完成回调。

  Boost库中的asio就使用了Proactor模式,其底层的异步I/O由操作系统提供,而异步事件的分发还是由epoll/kequeue/select等实现。

两者区别

  综上我们可以发现Reactor模式和Proactor模式的主要区别:

  1. Reactor实现同步I/O多路分发,Proactor实现异步I/O分发。

  如果只是处理网络I/O单线程的Reactor尚可处理,但如果涉及到文件I/O,单线程的Reactor可能被文件I/O阻塞而导致其他事件无法被分发。所以涉及到文件I/O最好还是使用Proactor模式,或者用多线程模拟实现异步I/O的方式。

  2. Reactor模式注册的是文件描述符的就绪事件,而Proactor模式注册的是完成事件。

  即Reactor模式有事件发生的时候要判断是读事件还是写事件,然后用再调用系统调用(read/write等)将数据从内核中拷贝到用户数据区继续其他业务处理。

  而Proactor模式一般使用的是操作系统的异步I/O接口,发起异步调用(用户提供数据缓冲区)之后操作系统将在内核态完成I/O并拷贝数据到用户提供的缓冲区中,完成事件到达之后,用户只需要实现自己后续的业务处理即可。

  3. 主动和被动

  Reactor模式是一种被动的处理,即有事件发生时被动处理。而Proator模式则是主动发起异步调用,然后循环检测完成事件。

  

  最后我们知道linux系统提供的异步I/O,只支持O_DIRECT,不能带缓存。因此出现了开源库libeio,它和Linux的异步I/O一样也是用多线程模拟,但是更高效。下图是libeio的异步I/O实现,是不是很像Proactor模式啊。

两种高效的事件处理模型:Reactor模式和Proactor模式的更多相关文章

  1. 两种高效的事件处理模式(Proactor和Reactor)

    典型的多线程服务器的线程模型 1. 每个请求创建一个线程,使用阻塞式 I/O 操作 这是最简单的线程模型,1个线程处理1个连接的全部生命周期.该模型的优点在于:这个模型足够简单,它可以实现复杂的业务场 ...

  2. 【Linux 网络编程】生动讲解 Reactor 模式与 Proactor 模式

    五种 I/O 模型 先花费点时间了解这几种 I/O 模型,有助于后面的理解. 阻塞 I/O 与非阻塞 I/O 阻塞和非阻塞的概念能应用于所有的文件描述符,而不仅仅是 socket.我们称阻塞的文件描述 ...

  3. I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor

    目录: <I/O模型之一:Unix的五种I/O模型> <I/O模型之二:Linux IO模式及 select.poll.epoll详解> <I/O模型之三:两种高性能 I ...

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

    原文出处: Alex Libman   译文出处:潘孙友   欢迎分享原创到伯乐头条 综述 这篇文章探讨并比较两种用于TCP服务器的高性能设计模式. 除了介绍现有的解决方案,还提出了一种更具伸缩性,只 ...

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

    [原文地址:http://www.cppblog.com/pansunyou/archive/2011/01/26/io_design_patterns.html] 综述 这篇文章探讨并比较两种用于T ...

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

    两种高性能 I/O 设计模式 Reactor 和 Proactor Reactor 和 Proactor 是基于事件驱动,在网络编程中经常用到两种设计模式. 曾经在一个项目中用到了网络库 libeve ...

  7. Reactor模式与Proactor模式

    该文章总结了网上资源对这两种模式的描述 原文地址:http://www.cnblogs.com/dawen/archive/2011/05/18/2050358.html 1.标准定义 两种I/O多路 ...

  8. 对于观察者模式,Reactor模式,Proactor模式的一点理解

    最近就服务器程序IO效率这一块了解一下设计模式中的Reacotr模式和proactor模式,感觉跟观察者模式有些类似的地方,网上也看了一些其他人对三者之间区别的理解,都讲得很仔细,在此根据自己的理解做 ...

  9. 同步异步阻塞非阻塞Reactor模式和Proactor模式 (目前JAVA的NIO就属于同步非阻塞IO)

    在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作. 在比较这两个模式之前,我们首先的搞明白 ...

随机推荐

  1. 简单粗暴详细讲解javascript实现函数柯里化与反柯里化

    函数柯里化(黑人问号脸)???Currying(黑人问号脸)???妥妥的中式翻译既视感:下面来一起看看究竟什么是函数柯里化: 维基百科的解释是:把接收多个参数的函数变换成接收一个单一参数(最初函数的第 ...

  2. requests + BeautifulSoup + json

    requests: response.text      以 unicode 格式显示响应的文本 response.content    以 二进制 格式显示响应的文本 BeautiSoup: sou ...

  3. ConcurrentHashMap 的工作原理及代码实现

    ConcurrentHashMap采用了非常精妙的"分段锁"策略,ConcurrentHashMap的主干是个Segment数组.Segment继承了ReentrantLock,所 ...

  4. Git使用教程 Windows使用Git全攻略

    在Windows上安装Git 我们需要先把Git的安装包下载下来,访问网址:https://git-for-windows.github.io/ 或者百度网盘:链接: https://pan.baid ...

  5. FreeSql (十)更新数据

    FreeSql支持丰富的更新数据方法,支持单条或批量更新,在特定的数据库执行还可以返回更新后的记录值. var connstr = "Data Source=127.0.0.1;Port=3 ...

  6. Net基础篇_学习笔记_第十一天_面向对象(关键字new和this)

     new关键字 new:用来创建对象的.Person zsPerson=new Person();new帮助我们做了3件事儿:1).在内存中开辟一块空间2).在开辟的空间中创建对象3).调用对象的构造 ...

  7. Linux 笔记 - 第四章 Linux 文件和目录管理

    博客地址:http://www.moonxy.com 1. 绝对路径和相对路径 绝对路径:由根目录 "/" 写起的.如:/usr/local/mysql 相对路径:不是由根目录 & ...

  8. Qt线程实现分析-moveToThread vs 继承

    最近抽空研究了下QThread,使用起来方式多种多样,但是在使用的同时,我们也应该去了解Qt的线程它到底是怎么玩儿的. Qt的帮助文档里讲述了2种QThread的使用方式,一种是moveToThrea ...

  9. Jmeter 接口自动化-脚本数据分离实例

    一. 背景:  为了让大家更加的了解Jmeter,并且使用起来游刃有余.这篇我们主要讲一下,如何优雅的使用Jmeter一步步的实现接口自动化,完成脚本与数据分离,把可能对Jmeter脚本的维护转移到c ...

  10. C++基础之关联容器

    关联容器 关联容器和顺序容器的本质区别:关联容器是通过键存取和读取元素.顺序容器通过元素在容器中的位置顺序存储和访问元素.因此,关联容器不提供front.push_front.pop_front.ba ...