zoukankan      html  css  js  c++  java
  • 四种主要的IO模型

    1 同步阻塞IO(Blocking IO)

    首先,解释一下这里的阻塞与非阻塞:

    • 阻塞IO,指的是需要内核IO操作彻底完成后,才返回到用户空间执行用户的操作.阻塞指的是用户空间程序的执行状态.传统的IO模型都是同步阻塞IO.在java中,默认创建的socket都是阻塞的.
    • 非阻塞IO,指的是用户空间的程序不需要等待内核IO操作彻底完成,可以立即返回用户空间执行用户的操作,即处于非阻塞的状态,与此同时内核会立即返回给用户一个状态值.
    • 简单来说:阻塞是指用户空间(调用线程)一直在等待,而不能干别的事,非阻塞是指用户空间(调用线程)拿到内核返回的状态值就返回自己的空间,IO操作可以干就干,不可以干,就去干别的事情.

    其次解释一下同步与异步:

    • 同步IO,是一种用户空间与内核空间的IO发起方式.同步IO是指用户空间的线程是主动发起IO请求的一方,内核空间是被动接受方.
    • 异步IO则反过来,是指系统内核是主动发起IO请求的一方,用户空间是被动接受方.

    在java应用进程中,默认情况下,所有的socket连接的IO操作都是同步阻塞IO.

    在阻塞式IO模型中,java应用程序从IO系统调用开始,知道系统调用返回,在这段时间内,java进程是阻塞的,返回成功后,应用程序开始处理用户空间的缓存区数据.

     举个例子,在java中发起一个socket的read读操作的系统调用流程大致如下

    1. 从java启动IO读的系统调用开始,用户线程就进入阻塞状态.
    2. 当系统内核收到read系统调用,就开始准备数据,一开始,数据可能还没有到达内核缓冲区(例如,还没有收到一个完整的socket数据包),这个时候内核就要等待.
    3. 内核一直等到完整的数据到达,就会将数据从内核缓冲区复制到用户缓冲区(用户空间的内存),然后内核返回结果(例如返回复制到用户缓冲区中的字节数)
    4. 直到内核返回后,用户线程才会解除阻塞状态,重新运行起来

    总之,阻塞IO的特点是:在内核进行IO执行的两个阶段,用户线程都被阻塞了.

    阻塞IO的优点是:应用程序开发起来非常简单,在阻塞等待数据期间,用户线程挂起,在阻塞期间,用户线程基本不会占用cpu资源.

    阻塞IO的缺点是:一般情况下,会为每个链接配备一个独立的线程,反过来说,就是一个线程维护一个连接的IO操作,在并发量高的场景下,需要大量的线程来维护大量的网络连接,内存线程切换的开销巨大,因此,基本上阻塞IO模型在高并发场景下是不可用的.

    2 同步非阻塞IO(None Blocking IO)

    这里所说的NIO模型,并非java中的NIO(new IO)库

    socket连接默认是阻塞模式,在linux系统下,可以通过设置将socket变成非阻塞模式.在NIO模型中,应用程序一旦开始IO程序调用

    1. 在内核缓冲区中没有数据的情况下,系统调用会立即返回,返回一个调用失败的信息.
    2. 在内核缓冲区中有数据的情况下,是阻塞的,直到数据从内核缓冲复制到用户进程缓冲.复制成功之后,系统调用返回成功,应用程序开始处理用户空间的缓冲数据

    举个例子:发起一个非阻塞socket的read操作的系统调用,流程如下:

    1. 在内核数据没有准备好的阶段,用户线程发起IO请求是,立即返回,所以为了读取到最终的数据,用户线程需要不断的发起IO系统调用.
    2. 内核数据到达后,用户线程发起系统调用,用户线程阻塞,内核开始复制数据,他会将数据从内核缓冲区复制到用户缓冲区,然后内核返回结果(例如返回复制到用户缓冲区的字节数).
    3. 用户线程读取到数据后,才会解除阻塞状态,重新运行起来.也就是说,用户进程需要经过多次的尝试,才会保证最终真正读到数据,而后续执行.

    同步非阻塞IO的特点:应用程序的线程需要不断地进行IO系统调用,轮询数据是否已经准备好,如果没有准备好,就继续轮询,知道完成IO系统调用位置.

    同步非阻塞IO的优点:每次发起的IO系统调用,在内核等待数据过程中,可以立即返回,用户线程不会阻塞,实时性较好.

    同步非阻塞IO的缺点:不断地轮询内核,这将占用大量的cpu时间,效率低下

    总体来说,在高并发场景下,同步非阻塞IO也是不可用的.

    3 IO多路复用(IO Multiplexing)

    即经典的Reactor反应器设计模式,也称为异步阻塞IO,java中的Selector选择器和Linux中的epoll都是这种模型.java中的new IO就是这种模型

    在IO多路复用模型中,引入了一种新的系统调用,查询IO的就绪状态,在Linux系统中,对应的系统调用为select/epoll系统调用.通过该系统调用,一个进程可以监视多个文件的描述符,一旦某个描述符就绪(一般指内核缓冲区可读/可写),内核能够将就绪的状态返回给应用程序,随后,应用程序根据就绪的状态,进行相应的IO系统调用.

    目前支持Io多路复用的系统调用,有select epoll等等.select系统调用,几乎所有的操作系统上都有支持,具有良好的跨平台特性.epoll是在linux2.6内核中提出的,是select系统调用的Linux增强版本.

    在IO多路复用模型中,通过select/epoll系统调用,单个应用程序的线程,可以不断地轮询成百上千的socket连接,当某个或者某些socket网络连接有IO就绪的状态,就返回对应的可以执行的读写操作.

    举个例子说明一个发起一个多路复用IO的read操作:

    1. 注册选择器,在这种模式中,首先,将需要read操作的目标socket网络连接,提前注册到select/epoll选择器中,java中对应的选择器类是Selector类,然后,才可以开启整个IO多路复用模型的轮询流程.
    2. 就绪状态的轮询,通过选择器的查询方法,查询注册过的所有socket连接的就绪状态,通过查询的系统调用,内核会返回一个就绪的socket列表,任何一个注册过的socket中的数据准备好了,内核缓冲区有数据(就绪)了,内核就讲该socket加入到就绪列表中.当用户线程调用select查询方法,整个线程会被阻塞住.
    3. 用户线程获得了就绪状态的列表后,根据其中的socket连接,发起read系统调用,用户线程阻塞.内核开始复制数据,将数据从内核缓冲区复制到用户缓冲区
    4. 复制完成后,内核返回结果,用户线程才会解除阻塞状态,用户线程读取到了数据,继续执行

      

     IO多路复用模型的特点: IO多路复用模型的IO涉及两种系统调用(System Call),另一种是select/epoll(就绪查询),一种是IO操作.IO多路复用模型建立在操作系统的基础设施之上,即操作系统的内核碧玺能够提供多路分离的系统调用select/epoll,和NIO模型相似,多路复用IO也需要轮询.负责select/epoll状态查询调用的线程,需要不断的进行select/epoll轮询,查找出达到IO操作就绪的socket连接,Io多路复用模型与同步非阻塞模型是由密切关系的,对于注册在选择器上的每一个可以查询的socket连接,一般都设置为同步非阻塞模型,仅是这一点,对应用户程序而言是无感知的.

    IO多路复用模型的有点: 与一个线程维护一个连接的阻塞IO模式相比,使用select/epoll的最大优势在于,一个选择器查询线程可以同时处理成千上万个连接,系统不必创建大量的线程,也不必维护这些线程,从而大大减小系统的开销.

    IO多路复用模型的缺点: 本质上,select/epoll系统调用时阻塞式的,属于同步IO,都需要在读写事件就绪后,由系统调用本身负责进行读写,也就是说,这个读写过程是阻塞的.

    4 异步IO(Asynchronous IO)

    异步IO,指的是用户与内核空间的调用方式反过来,用户口空间的线程变为被动接受者,而内核空间成了主动调用者.有点类似于java中比较经典的回调模式,用户空间的线程向内核空间注册了各种IO事件的回调函数,由内核去主动调用.

    异步IO模型简称AIO,AIO的基本流程是:用户线程通过系统调用,想内核注册某个IO操作,内核在整个IO操作(包括数据准备,数据复制)完成后,通知用户程序,用户执行后续的业务操作

    在异步IO模型中,在整个内核的数据处理过程中,报错内核将数据从网络物理设备(网卡)读取到内核缓冲区,将内核缓冲区的数据复制到用户缓冲器,用户都不需要阻塞

    举例在AIO模型下,发起read操作,流程如下:

    1. 当用户线程发起来read系统调用,立刻就可以开始去做其他的事,用户线程不阻塞.
    2. 内核就就开始了IO的第一个阶段:准备数据.等到数据准备好了,内核就会将数据从内核缓冲区,复制到用户缓冲区,
    3. 内核会给用户线程发送一个信号,或者回调用户线程注册的回调接口,告诉用户线程read操作完成了
    4. 用户线程读取用户缓冲区的数据,完成后续操作

     异步IO模型的特点:在内核等待数据和复制数据的两个阶段,用户线程都不是阻塞的.用户线程需要接受内核的IO操作完成的事情或者用户线程需要注册一个IO操作完成的回调函数,正因为如此,异步IO有时候也叫信号驱动IO

    异步IO模型的缺点:应用程序仅需要进行事件的注册与接收,其他的工作都留给了操作系统,也就是说,需要底层内核提供支持.

    理论上来说,异步IO是真正的异步输入输出,他的吞吐量高于Io多路复用模型的吞吐量.就目前而言,windows系统下通过IOCP实现了真正的异步IO,而在Linux系统下,异步IO模型在2.6版本才引入,目前并不完善,其底层实现仍使用epoll与Io多路复用相同,因此性能上没有明显的优势

    大多数的高并发服务器端的程序,一般都是基于linux系统的,因而,目前这类高并发网络应用程序的开发,大多采用IO多路复用模型,大名鼎鼎的Netty框架,使用的也是IO多路复用模型,而不是异步IO模型

  • 相关阅读:
    selenium自动化测试CSS定位
    思想重铸(转自知乎)
    闭环思维
    20170503xlVBA房地产数据分类连接
    20170517xlVBA添加数据透视表
    20170617xlVBA销售数据分类汇总
    20170621xlVBA跨表转换数据
    20170612xlVBA含方框文档填表
    20170612xlVBA多文件多类别分类求和匹配
    20170617xlVBA调查问卷基础数据分类计数
  • 原文地址:https://www.cnblogs.com/xiaodu9499/p/13897467.html
Copyright © 2011-2022 走看看