IO设计模式之Reactor和Proactor

前言

上面文章中,我们提到不同的操作系统实现的io策略可能不一样,即使是同一个操作系统也可能存在多重io策略,常见如linux上的select,poll,epoll,面对这么多不同类型的io接口,这里需要一层抽象api来完成,所以就演变出来两种高性能的io的设计模式,分别是Reactor(同步IO)和Proactor(异步IO)。

一般情况下,I/O 复用机制需要事件分享器(event demultiplexor)。 事件分离器的作用,即将那些读写事件源分发给各读写事件的处理者,就像送快递的小哥,拉着一三轮车快递停到了小区的快递收发区,然后打电话通知,谁谁谁的快递到了快来拿吧;谁谁谁要邮寄出去的快递,快来这里邮寄填写表格。这里面拿快递就类似IO的读请求,发快递就类似IO的写请求,而快递小哥则是事件分享器,并负责完成送和收快递的两种事件。开发人员在开始的时候需要在分享器那里注册感兴趣的事件,并提供相应的处理者(event handlers),或者是回调函数; 事件分享器在适当的时候会将请求的事件分发给这些handler或者回调函数。

关于Reactor

Reactor英文意思为反应器,类似于核能的反应堆一样,所有的能量都源源不断从这里传出.或者更贴切一点叫事件的分发器。在Reactor中,事件分离器负责等待文件描述符或socket为读写操作准备就绪,然后将就绪事件传递给对应的处理器,最后由处理器负责完成实际的读写工作。

Linux epoll 使用 Reactor 模式。Reactor 模式使用同步 I/O(一般来说)。Reactor 的标准(典型)的工作方式是:

(1)应用程序注册读就绪事件和相关联的事件处理器

(2)Reactor阻塞等待内核事件通知

(3)Reactor收到通知,然后分发可读写事件(读写准备就绪)到用户事件处理函数

(4)用户读取数据,并处理数据

(5)事件处理器完成实际的读操作,处理读到的数据,注册新的事件,然后返还控制权。

这里面需要注意,事件分离器仅仅发现当有io事件都写就绪的时候,会通知用户线程来读取数据,这一步相当于io阻塞的第二个阶段,从内核空间拷贝数据到用户空间是由用户线程完成的,所以Reactor模式实际上还属于同步IO的模式,当然为了架构更灵活和性能更好,一般情况下事件分离器和实际的处理器线程是分开的,类似Netty里面的boss线程组合worker线程组一样。

关于Proactor

Proactor英文意思前摄器,是一种异步的IO设计模式。这种模式更加理想,但真正支持纯异步的io模式,目前只有windows的Windows IO completion port.(iocp)模型。

Windows iocp 使用 Praactor 模式。Praactor 模式使用异步 I/O(一般来说)。Praactor 的标准(典型)的工作方式是:

(1)应用程序初始化一个异步读取操作,然后注册相应的事件处理器,此时事件处理器不关注读取就绪事件,而是关注读取完成事件,这是区别于Reactor的关键。

(2)事件分离器等待读取操作完成事件

(3)在事件分离器等待读取操作完成的时候,操作系统调用内核线程完成读取操作,并将读取的内容放入用户传递过来的缓存区中。这也是区别于Reactor的一点,Proactor中,应用程序需要传递缓存区。

(4)事件分离器捕获到读取完成事件后,激活应用程序注册的事件处理器,事件处理器直接从缓存区读取数据,而不需要进行实际的读取操作。

从上面的描述中能够看到,Proactor模式中,操作系统相当于直接把IO操作的两阶段工作都给干了,这也要求应用程序在注册异步任务时,需要传递一个缓存区,用来存放结果数据。这里面事件分离器关注的是io的完成事件,而不是就绪时间,当分离器通知应用程序时,应用程序可以直接就能处理数据了。

总结

关于Reactor和Proactor这两种IO设计模式,我们举个实际生活中的例子:Reactor模式就是快递员在楼下,给你打电话告诉你快递到了,你需要自己下楼来拿快递。而在Proactor模式下,快递员直接将快递送到家里面的指定位置。

Reactor和Proactor是两种高性能的IO设计模式,分别用于同步IO和异步IO的策略,可以看出它们都是采用的IO复用的模式,都是对某个IO事件的事件通知(即告诉某个模块,这个IO操作可以进行或已经完成)。在结构上,两者也有相同点:demultiplexor负责提交IO操作(异步)、查询设备是否可操作(同步),然后当条件满足时,就回调handler;

不同点在于,异步情况下(Proactor),当回调handler时,表示IO操作已经完成(数据已从系统内核拷贝到程序内存);同步情况下(Reactor),回调handler时,表示IO设备可以进行某个操作(can read or can write,数据准备就绪,但是用户需要自己将数据从系统内核拷贝到程序内存)。

原文发布于微信公众号 - 我是攻城师(woshigcs)

原文发表时间:2018-11-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏信安之路

Windows环境下的信息收集

通常我们在渗透测试过程中,遇到的Windows的环境是最多的,然而在拿到一台windows系统权限之后,我们要进行横向或者纵向渗透,这是针对windows的信息...

1000
来自专栏FreeBuf

弹性边界:如何利用环境变量进行提权

简介 尽管进程都设置了环境变量,它们往往被用户,开发者甚至是系统本身所忽略。对于一个像样的系统来说,环境变量就是其最根本,这里的系统包括但不仅限于Unix (...

2767
来自专栏武军超python专栏

2018年7月30日初步熟悉ubuntu操作系统

今天遇到的新单词: initialize  v 初始化、 torrent n 种子 alien n外星人  ware n商品   alienware ...

1434
来自专栏Vamei实验室

Linux开机启动(bootstrap)

计算机开机是一个神秘的过程。我们只是按了开机键,就看到屏幕上的进度条或者一行行的输出,直到我们到达登录界面。然而,计算机开机又是个异常脆弱的过程,我们满心期望的...

2458
来自专栏Debian社区

使用 tmate 分享你的终端会话

tmate 的意思是 teammates,它是 tmux 的一个分支,并且使用相同的配置信息(例如快捷键配置,配色方案等)。它是一个终端多路复用器,同时具有即时...

1053
来自专栏安恒信息

预警 | Struts2 REST插件存在远程代码执行漏洞(CVE-2017-9805)

漏洞描述 Struts2 是 Apache 软件基金会负责维护的一个基于MVC设计模式的 Web 应用框架开源项目。 Struts2的REST插件使用带有XSt...

36114
来自专栏漫漫前端路

HTTP协议 - 从URI开始

URI, 既是统一资源标识符号,每个 Web 服务器都有一个 URI 标识符,它在世界范围内唯一标识并定位信息资源。

1484
来自专栏网商云

小白教程--centos7修改ssh远程端口

新账号关联我们公司购买腾讯云产品,有优惠哦!联系电话:13430587834(微信同号)

5284
来自专栏GAN&CV

Ubuntu16.04安装opencv2&&ImportError: No module named cv2.cv

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_25737169/article/d...

3483
来自专栏非著名程序员

如何优化 Android Studio 启动、编译和运行速度?

?作为一名 Android 程序员,选择一个好的 IDE 工具可以使开发变得非常高效,很多程序员喜欢使用 Google 的 Android Studio来进行...

1936

扫码关注云+社区

领取腾讯云代金券