专栏首页程序生涯两种IO模式:Proactor与Reactor模式

两种IO模式:Proactor与Reactor模式

在高性能的I/O设计中,有两个比较著名的模式Reactor和Proactor模式,其中Reactor模式用于同步I/O,而Proactor运用于异步I/O操作。

在比较这两个模式之前,我们首先的搞明白几个概念,什么是阻塞和非阻塞,什么是同步和异步

?同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发IO操作并等待或者轮询的去查看IO操作是否就绪,而异步是指用户进程触发IO操作以后便开始做自己的事情,而当IO操作已经完成的时候会得到IO完成的通知(异步的特点就是通知)。

而阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作函数的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入函数会立即返回一个状态值。

一般来说I/O模型可以分为:同步阻塞,同步非阻塞,异步阻塞,异步非阻塞IO

同步阻塞IO:

在此种方式下,用户进程在发起一个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,用户进程才能运行。JAVA传统的IO模型属于此种方式!

同步非阻塞IO:

在此种方式下,用户进程发起一个IO操作以后边可返回做其它事情,但是用户进程需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费。其中目前JAVA的NIO就属于同步非阻塞IO。

异步阻塞IO:

此种方式下是指应用发起一个IO操作以后,不等待内核IO操作的完成,等内核完成IO操作以后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问IO是否完成,那么为什么说是阻塞的呢?因为此时是通过select系统调用来完成的,而select函数本身的实现方式是阻塞的,而采用select函数有个好处就是它可以同时监听多个文件句柄(如果从UNP的角度看,select属于同步操作。因为select之后,进程还需要读写数据),从而提高系统的并发性!

异步非阻塞IO:

在此种模式下,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。目前Java中还没有支持此种IO模型。

搞清楚了以上概念以后,我们再回过头来看看,Reactor模式和Proactor模式。

(其实阻塞与非阻塞都可以理解为同步范畴下才有的概念,对于异步,就不会再去分阻塞非阻塞。对于用户进程,接到异步通知后,就直接操作进程用户态空间里的数据好了。)

首先来看看Reactor模式,Reactor模式应用于同步I/O的场景。我们分别以读操作和写操作为例来看看Reactor中的具体步骤:

读取操作:

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

2. 事件分离器等待事件的发生

3. 当发生读就绪事件的时候,事件分离器调用第一步注册的事件处理器

4. 事件处理器首先执行实际的读取操作,然后根据读取到的内容进行进一步的处理

写入操作类似于读取操作,只不过第一步注册的是写就绪事件。

下面我们来看看Proactor模式中读取操作和写入操作的过程:

读取操作:

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

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

3. 在事件分离器等待读取操作完成的时候,操作系统调用内核线程完成读取操作(异步IO都是操作系统负责将数据读写到应用传递进来的缓冲区供应用程序操作,操作系统扮演了重要角色),并将读取的内容放入用户传递过来的缓存区中。这也是区别于Reactor的一点,Proactor中,应用程序需要传递缓存区。

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

Proactor中写入操作和读取操作,只不过感兴趣的事件是写入完成事件。

从上面可以看出,Reactor和Proactor模式的主要区别就是真正的读取和写入操作是有谁来完成的,Reactor中需要应用程序自己读取或者写入数据,而Proactor模式中,应用程序不需要进行实际的读写过程,它只需要从缓存区读取或者写入即可,操作系统会读取缓存区或者写入缓存区到真正的IO设备.

综上所述,同步和异步是相对于应用和内核的交互方式而言的,同步 需要主动去询问,而异步的时候内核在IO事件发生的时候通知应用程序,而阻塞和非阻塞仅仅是系统在调用系统调用的时候函数的实现方式而已。

//////////////////////////////////////////////

说到阻塞,首先得说说I/O等待。I/O等待是不可避免的,那么既然有了等待,就会有阻塞,但是注意,我们说的阻塞是指当前发起I/O操作的进程被阻塞 同步阻塞I/O便是指,当进程调用某些涉及I/O操作的系统调用或库函数时,比如accept()(注意accept也算在了i/o操作)、send()、recv()等,进程便暂停下来,等待I/O操作完成再继续运行。这是一种简单而有 效的I/O模型,它可以和多进程结合起来有效的利用CPU资源,但是代价就是多进程的大量内存开销。

同步阻塞 进程坐水,就不能烧粥 同步非阻塞 类似于用一个进程坐水,烧粥. while(true){if... if... } 好处就是一个进程处理多个i/o请求. 劣势就是需要不停的轮询.

区别在于等不等待数据就绪. 因为数据占了等待的80%时间. 同步非阻塞的优势就是一个进程里同时处理多个I/O操作。

在同步阻塞I/O中,进程实际上等待的时间可能包括两部分,一个是等待数据的就绪,另一个是等待数 据的复制,对于网络I/O来说,前者的时间可能要更长一些。 与此不同的是,同步非阻塞I/O的调用不会等待数据的就绪,如果数据不可读或者不可写,它会立即返 回告诉进程。

比如我们使用非阻塞recv()接收网络数据的时候,如果网卡缓冲区中没有可接收的数据,函数就及时返回,告诉进程没有数据可读了。相比于阻塞I/O,这种非阻塞I/O结合反复的轮询来尝试 数据是否就绪,防止进程被阻塞,最大的好处便在于可以在一个进程里同时处理多个I/O操作。但正是由于需要进程执行多次的轮询来查看数据是否就绪,这花费了大量的CPU时间,使得进程处于忙碌等待状态。

非阻塞I/O一般只针对网络I/O有效,我们只要在socket的选项设置中使用O_NONBLOCK即可,这样对于该socket的send()或recv()便采用非阻塞方式。 如果服务器想要同时接收多个TCP连接的数据,就必须轮流对每个socket调用接收数据的方法,比如recv()。不管这些socket有没有可以接收的数据,都要询问一遍,假如大部分socket并没有数据可以接收,那么进程便会浪费很多CPU时间用于检查这些socket,这显然不是我们所希望看到的。

同步和异步,阻塞和非阻塞,有些混用,其实它们完全不是一回事,而且它们修饰的对象也不相同。 阻塞和非阻塞是指当进程访问的数据如果尚未就绪,进程是否需要等待,简单说这相当于函数内部的实现区别,也就是未就绪时是直接返回还是等待就绪;

而同步和异步是指访问数据的机制,同步一般指主动请求并等待I/O操作完毕的方式,当数据就绪后在读写的时候必须阻塞(区别就绪与读写二个阶段,同步的读写必须阻塞),异步则指主动请求数据后便可以继续处理其它任务,随后等待I/O,操作完毕的通知,这可以使进程在数据读写时也不阻塞。(等待"通知")

多数情况下,Web服务器对这些请求采用基于队列的自由竞争,通过多执行流(多进程或多线程)来充分占 用CPU以及I/O资源,减少任何无辜的等待时间,这其中包括了很多种具体实现的并发策略, 在实际应用中,特别是Web服务器,同时处理大量的文件描述符是必不可少的.多路I/O就绪通知的出现,提供了对大量文件描述符就绪检查的高性能方案,它允许进程(比如电子屏,会闻到各个饭馆做好饭菜的味道)通过一种方法来同时监视所有文件描述符,并可以快速获得所有就绪的文件描述符,然后只针对这些文件描述符进行数据访问。 回到买面条的故事中,假如你不止买了一份面条,还在其它几个小吃店买了饺子、粥、馅饼等,因为一起逛街的朋友看到你的面条后也饿了。这些东西都需要时间来等待制作。在同步非阻塞I/O模型中,你 要轮流不停的去各个小吃店询问进度,痛苦不堪。现在引入多路I/O就绪通知后,小吃城管理处给大厅安装了一块电子屏幕,以后所有小吃店的食物做好后,都会显示在屏幕上,这可真是个好消息,你只需 要间隔性的看看大屏幕就可以了,也许你还可以同时逛逛附近的商店,在不远处也可以看到大屏幕。

多路就绪:1.强调多路. 2.只针对请求数据是否就绪.不针对i/o读写 epoll针对的是这样的场景.

select, epoll都只需要进程(我)被动接收到数据就绪(面条)"通知".符合异步的定义. 不需要一直在饭馆等(同步阻塞).或轮询(同步非阻塞).

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

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 简单理解reactor和proactor

    reactor是关心就绪事件,比如可读了,就通知你,就像epoll_wait 。proactor关心的是完成比如读完了,就通知你。

    春哥大魔王
  • IO设计模式之Reactor和Proactor

    上面文章中,我们提到不同的操作系统实现的io策略可能不一样,即使是同一个操作系统也可能存在多重io策略,常见如linux上的select,poll,epoll,...

    我是攻城师
  • IO事件驱动设计实现

    在web体系中,相比线程连接架构设计而言,事件驱动设计更满足我们实现一个高性能IO的web服务,这点在高性能IO编程一文已经有讲述.对此,我们接下来将要展开如何...

    keithl
  • 整天背诵五种I/O模型/epoll区别,换个马甲确不认识了!

    Java 中的 BIO、NIO和 AIO 理解为是 Java 语言对操作系统的各种 IO 模型的封装。

    程序员小王
  • JAVA高性能I/O设计模式

    同步阻塞模式。在JDK1.4以前,使用Java建立网络连接时,只能采用BIO方式,在服务器端启动一个ServerSocket,然后使用accept等待客户端请求...

    cloudskyme
  • 五分钟快速理解 Reactor 模型

    本文将介绍基于进程/线程模型,服务器如何处理请求。值得说明的是,具体选择线程还是进程,更多是与平台及编程语言相关。

    架构师修炼
  • 原来 8 张图,就能学废 Reactor 和 Proactor

    别小看这两个东西,特别是 Reactor 模式,市面上常见的开源软件很多都采用了这个方案,比如 Redis、Nginx、Netty 等等,所以学好这个模式设计的...

    小林coding
  • Linux高性能IO网络模型对比分析:Reactor vs Proactor

    随着互联网的发展,面对海量用户高并发业务,传统的阻塞式的服务端架构模式已经无能为力。本文旨在为大家提供有用的高性能网络编程的I/O模型概览以及网络服务进程模型的...

    sunsky
  • IO多路复用机制详解

    (2)同步非阻塞IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。注意这里所说的NI...

    lyb-geek
  • 高性能IO模型浅析

    服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型。 (2)同步非阻塞IO(Non...

    李海彬
  • 高性能IO模型浅析

    服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种: (1)同步阻塞IO(Blocking IO):即传统的IO模型。 (2)同步非阻塞IO(Non...

    李海彬
  • 彻底搞懂Reactor模型和Proactor模型

    在高性能的I/O设计中,有两个著名的模型:Reactor模型和Proactor模型,其中Reactor模型用于同步I/O,而Proactor模型运用于异步I/O...

    全菜工程师小辉
  • Java NIO浅析

    NIO(Non-blocking I/O,在Java领域,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到...

    美团技术团队
  • Java NIO浅析

    作者:美团点评技术团队 链接:https://zhuanlan.zhihu.com/p/23488863 来源:知乎 著作权归作者所有。商业转载请联系作者...

    bear_fish
  • 常见多线程与并发服务器设计方案举例

    一、3点基础知识 1、一个主机的端口号为所有进程所共享,但普通用户进程绑定bind不了一些特殊端口号如20、80等。      多个进程不能同时监听listen...

    s1mba
  • Java NIO之理解I/O模型(二)

    上一篇文章讲解了I/O模型的一些基本概念,包括同步与异步,阻塞与非阻塞,同步IO与异步IO,阻塞IO与非阻塞IO。这次一起来了解一下现有的几种IO模型,以及高效...

    纪莫
  • Boost ASIO proactor 浅析

    Boost ASIO proactor 浅析 前情提要: Boost asio 的socket的异步非阻塞模式才有的是proactor模式,当IO操作介绍后回调...

    知然
  • 并发模型的一些概念以及设计探讨

    阿伟
  • socket&io高性能

    最近看到篇好文章《IO多路复用》,记得早期学习时,也去探索过select、poll、epoll的区别,但后来也是没有及时记录总结,也忘记了,学习似乎就是在记忆与...

    码农戏码

扫码关注云+社区

领取腾讯云代金券