高性能I/O设计模式Reactor和Proactor
系统I/O 可分为阻塞型, 非阻塞同步型,非阻塞异步型。 (Linux对aio支持的不完整,所以linux上用Reactor比较多;Proactor需要系统API支持真正的“异步”)
阻塞型I/O意味着控制权直到调用操作结束才会返回到调用者手里。因此调用者被阻塞了, 这段时间了做不了任何其它事情. 更郁闷的是,在等待IO结果的时间里,调用者所在线程此时无法腾出手来去响应其它的请求。拿read()操作来说吧, 调用此函数的代码会一直僵在此处直至它所读的socket缓存中有数据到来.
相比之下,非阻塞同步是会立即返回控制权给调用者的。调用者不需要等等,它从调用的函数获取两种结果:要么此次调用成功进行了;要么系统返回错误标识告诉调用者当前资源不可用,你再等等或者再试度看吧。比如一个read()操作对sockect在非阻塞模式下,返回成功读取的字节数,或者失败返回特殊码-1设置为EWOULBLOCK/EAGAIN,告诉调用read()者"数据还没准备好,你稍后再试".
在非阻塞异步调用中,稍有不同。调用函数在立即返回时,还告诉调用者,这次请求已经开始了。系统会使用另外的资源或者线程来完成这次调用操作,并在完成的时候知会调用者(比如通过回调函数)。拿Windows的ReadFile()或者POSIX的aio_read()来说,调用它之后,函数立即返回,操作系统在后台同时开始读操作。 操作系统提供了异步的模式来传输网络数据,即:应用程序把要发送的数据交给操作系统,操作系统把数据放在系统缓冲区后应用程序该干嘛干嘛去。操作系统发送完成后,会给应用系统一个回执,告诉应用程序:刚才那个包发送完成了!
在以上三种IO形式中,非阻塞异步是性能最高、伸缩性最好的。 Proactor模式在单CPU单核系统应用中有着无可比拟的优势。
二者的差异,以读操作为例(写操作类似)。
在Reactor中实现读:
- 注册读就绪事件和相应的事件处理器
- 事件分离器等待事件
- 事件到来,激活分离器,分离器调用事件对应的处理器。
- 事件处理器完成实际的读操作,处理读到的数据,注册新的事件,然后返还控制权。
与Proactor(真异步)中的读过程比较:
- 事件处理者直接发起异步读操作(注意:操作系统必须支持异步IO)。在这种情况下,处理器无视IO就绪事件,它关注的是完成事件。
- 事件分离器等待操作完成事件 (比较下与Reactor的不同)
- 在分离器等待过程中,操作系统利用并行的内核线程执行实际的读操作,并将结果数据存入用户自定义缓冲区,通知事件分离器读操作完成。
- 事件分离器呼唤之前的事件处理者事情搞定了。
- 事件处理器处理用户自定义缓冲区中的数据,然后启动一个新的异步操作,并将控制权返回事件分离器。
改进的解决方案
将Reactor稍做调整,模拟成异步的Proactor模型(主要是在事件分离器里完成本该事件处理者做的实际读写工作,我们称这种方法为"模拟异步")。 下面的示例可以看看read操作是如何完成的:
- 事件处理者宣称对读事件感兴趣,并提供了用于存储结果的缓存区、读数据长度等参数;
- 分离器等待(比如通过select());
- 当有事件到来(即可读),分离器被唤醒, 分离器去执行非阻塞的读操作(前面事件处理者已经给了足够的信息了)。读完后,它去通知事件处理者。
- 事件处理器处理用户自定义缓冲区的数据,注册新的事件(当然同样要给出数据缓冲区地址,需要读取的数据量等信息),最后将控制权返还分离器。
我们看到,通过为分离者添加一些功能,可以让Reactor模式转换为Proactor模式。所有这些被执行的操作,其实是和Reactor模型应用时完全一致的。我们只是把工作打散分配给不同的角色去完成而已。这样并不会有额外的开销,也不会有性能上的的损失,我们可以再仔细看看下面的两个过程,他们实际上完成了一样的事情:
标准的经典的 Reactor模式:
- 步骤 1) 等待事件 (Reactor 的工作)
- 步骤 2) 发"已经可读"事件发给事先注册的事件处理者或者回调 ( Reactor 要做的)
- 步骤 3) 读数据 (用户代码要做的)
- 步骤 4) 处理数据 (用户代码要做的)
模拟的Proactor模式:
- 步骤 1) 等待事件 (Proactor 的工作)
- 步骤 2) 读数据(这里变成了让 Proactor 做这个事情)
- 步骤 3) 把数据已经准备好的消息给用户处理函数,即事件处理者(Proactor 要做的)
- 步骤 4) 处理数据 (用户代码要做的)
在没有底层异步I/O API支持的操作系统,这种方法可以帮我们隐藏掉socket接口的差异(无论是性能还是其它), 提供一个完全可用的统一"异步接口"。这样我们就可以开发真正平台独立的通用接口了。
Boost.Asio类库,其就是以Proactor这种设计模式来实现,参见:Proactor(The Boost.Asio library is based on the Proactor pattern. This design note outlines the advantages and disadvantages of this approach.),其设计文档链接:http://asio.sourceforge.net/boost_asio_0_3_7/libs/asio/doc/design/index.html
所有同步等待策略可划分为两组:
- edge-triggered (e.g. Linux实时信号) - signal readiness only when socket became ready (changes state);
- level-triggered (e.g.
select(),poll(), /dev/poll) - readiness at any time.
如:ACE技术论文集-第8章 前摄器(Proactor):用于为异步事件多路分离和分派处理器的对象行为模式
ACE技术论文集-第7章 ACE反应堆(Reactor)的设计和使用:用于事件多路分离的面向对象构架
ACE程序员教程-第6章 反应堆(Reactor):用于事件多路分离和分派的体系结构模式
高性能I/O设计模式Reactor和Proactor的更多相关文章
- 两种高性能 I/O 设计模式 Reactor 和 Proactor
两种高性能 I/O 设计模式 Reactor 和 Proactor Reactor 和 Proactor 是基于事件驱动,在网络编程中经常用到两种设计模式. 曾经在一个项目中用到了网络库 libeve ...
- I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor
目录: <I/O模型之一:Unix的五种I/O模型> <I/O模型之二:Linux IO模式及 select.poll.epoll详解> <I/O模型之三:两种高性能 I ...
- 【转载】高性能I/O设计模式Reactor和Proactor
转载自:http://blog.csdn.net/roger_77/article/details/1555170 昨天购买了<程序员>杂志 2007.4期,第一时间去翻阅了一遍,其中有一 ...
- I/O模型系列之四:两种高性能IO设计模式 Reactor 和 Proactor
不同的操作系统实现的io策略可能不一样,即使是同一个操作系统也可能存在多重io策略,常见如linux上的select,poll,epoll,面对这么多不同类型的io接口,这里需要一层抽象api来完成, ...
- 两种高性能I/O设计模式(Reactor/Proactor)的比较
原文出处: Alex Libman 译文出处:潘孙友 欢迎分享原创到伯乐头条 综述 这篇文章探讨并比较两种用于TCP服务器的高性能设计模式. 除了介绍现有的解决方案,还提出了一种更具伸缩性,只 ...
- [转]两种高性能I/O设计模式(Reactor/Proactor)的比较
[原文地址:http://www.cppblog.com/pansunyou/archive/2011/01/26/io_design_patterns.html] 综述 这篇文章探讨并比较两种用于T ...
- 高性能IO设计的Reactor和Proactor模式(转)
在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作. 在比较这两个模式之前,我们首先的搞明白 ...
- I/O模型之四:Java 浅析I/O模型(BIO、NIO、AIO、Reactor、Proactor)
目录: <I/O模型之一:Unix的五种I/O模型> <I/O模型之二:Linux IO模式及 select.poll.epoll详解> <I/O模型之三:两种高性能 I ...
- IO设计模式:Reactor和Proactor对比
IO设计模式:Reactor和Proactor对比 平时接触的开源产品如Redis.ACE,事件模型都使用的Reactor模式:而同样做事件处理的Proactor,由于操作系统的原因,相关的开源产品也 ...
随机推荐
- Android学习笔记(SQLite的简单使用)
1.SQLite介绍 SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中.它是D.RichardHipp建立的公有领域项目.它的设计目标是嵌入式的,而且 ...
- why slow thinking wins
今天Hacker News上的一篇文章<为什么想得慢的人能赢>引起了广泛的讨论. 网友Scott Burson在文章后评论说:"之前,我雇佣了一位TopCoder冠军,原本预计他 ...
- MvvmCross[翻译] 使用Xamarin与MvvmCross完成一个跨平台App
总览 原文:https://github.com/MvvmCross/MvvmCross/wiki/Tip-Calc-A-first-app 我们所做的第一个Model-View-ViewModel( ...
- Java小例子(学习整理)-----学生管理系统-控制台版
1.功能介绍: 首先,这个小案例没有使用数据库,用集合的形式暂时保存数据,做测试! 功能: 增加学生信息 删除学生信息 修改学生信息 查询学生信息: 按照学号(精确查询) 按照姓名(模糊查询) 打 ...
- ACM HDU Primes(素数判断)
Problem Description Writea program to read in a list of integers and determine whether or not eachnu ...
- ACM YTU 《挑战编程》第一章 入门 Problem E: Graphical Editor
Description Graphical editors such as Photoshop allow us to alter bit-mapped images in the same way ...
- 网站开发常用jQuery插件总结(九)侧边栏插件pageslide
一.pageslide插件功能 实现现实隐藏侧边栏的功能.插件可以读取另个一html,也可以是当前页面中的元素. 二.pageslide官方地址 http://srobbin.com/jquery-p ...
- demo_04绘制三角形
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- CentOS6.5使用本地光盘做yum源 (参考:http://www.jb51.net/os/RedHat/43343.html)
一.使用光盘做yum源安装软件 mkdir /media/CentOS #新建CentOS挂载目录 mount -t auto /dev/cdrom /media/CentOS #挂载CentOS光 ...
- php 接收 Android 传递的json 转 数组 问题
过程:Android 拼接一个 json格式的数据 传值 ,php 接收 转为数组 json_decode 取值 json格式为:{"goods":{"1000 ...