高性能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,由于操作系统的原因,相关的开源产品也 ...
随机推荐
- phpmyadmin备份小问题
不要将imformation——shame或者mysql等备份,要有选择的备份表 关注我的新浪微博
- ERROR ITMS-90167: "No .app bundles found in the package"
http://stackoverflow.com/questions/37838487/error-itms-90167-no-app-bundles-found-in-the-package 简单说 ...
- O-C相关-03:面向对象概念的具体介绍
1.面向对象的概念 面向对象(object-oriented ;简称: OO) 至今还没有统一的概念,我这里把它定义为:按人们认识客观世界的系统思维方式,采用基于对象(实体)的概念建立模型,模拟客观世 ...
- WPF 窗体中的 Canvas 限定范围拖动 鼠标滚轴改变大小
xaml代码: <Canvas Name="movBg"> <Canvas.Background> <LinearGradientBrush EndP ...
- JSONP技术原理及实现
跨域问题一直是前端中常见的问题,每当说到跨域,第一浮现的技术必然就是JSONP JSONP在我的理解,它并不是ajax,它是在文档中插入一个script标签,创建_callback方法,通过服务器配合 ...
- IE6 兼容问题总结
1 IE6,IE7下设置body{overflow:hidden;}失效Bug
- php 微信3 自定义菜单
<pre name="code" class="php"><pre name="code" class="htm ...
- MYSQL 不排序
mysql: SELECT * FROM EVENT WHERE eventId IN(443,419,431,440,420,414,509) ORDER BY INSTR(',443,419,43 ...
- html中子div用了浮动怎样让父div的大小自动撑开(清除浮动)
浮动子div撑开父div的几种方法: (1)在父div中在添加一个清除浮动的子div<div style=" clear:both;"></div>,该di ...
- html5中的常用的库
JQuery是继prototype之后又一个优秀的Javascript库.它是轻量级的js库 ,它兼容CSS3,还兼容各种浏览器(IE 6.0+, FF1.5+, Safari 2.0+, Opera ...