1. Unix的五种I/O模型

从上往下:阻塞程度(高-----低)I/O效率  (低-----高)

  1. 阻塞I/O(Blocking I/O):传统的IO模型

  2. 非阻塞I/O(Non-Blocking I/O): 注意这里所说的NIO并非Java的NIO(New IO)库。

  3. I/O多路复用(I/O Multiplexing): 经典的Reactor设计模式,有时也称异步阻塞IO,Java中的Selector和Linux中的epoll都是这种模型。

  4. 信号驱动I/O(Signal Driven I/O)

  5. 异步I/O(Asychronous I/O): 经典的Proactor设计模式,也称为异步非阻塞IO。

2. Unix的输入操作

Unix的一个输入操作一般有两个不同的阶段:

  第一步,待数据准备好。(目标:减小便可以提高效率)

  第二步,从内核到进程拷贝数据。

对于一个套接口上的输入操作(两次拷贝):

  第一步,待数据到达网络,当分组到达时,它被拷贝到内核中的某个缓冲区。

  第二步,将数据从内核缓冲区拷贝到应用缓冲区。

3. 阻塞I/O

  阻塞I/O:应用程序调用一个IO函数,导致应用程序阻塞,如果数据已经准备好,从内核拷贝到用户空间,否则一直等待下去。  
  在linux中,默认情况下所有的socket都是blocking,一个典型的读操作流程大概是这样:
  当用户进程调用了recvfrom这个系统调用,
  第一步,kernel就开始了IO的第一个阶段,准备数据(对于网络IO来说,很多时候数据在一开始还没有到达。比如,还没有收到一个完整的UDP包。这个时候kernel就要等待足够的数据到来)。这个过程需要等待,也就是说数据被拷贝到操作系统内核的缓冲区中是需要一个过程的。而在用户进程这边,整个进程会被阻塞(当然,是进程自己选择的阻塞)。
  第二步,当kernel一直等到数据准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来。
准备好了,它就会将数据从kernel中拷贝到用户内存,然后kernel返回结果,用户进程才解除block的状态,重新运行起来。
 所以,blocking IO的特点就是在IO执行的两个阶段都被block了。

4. 非阻塞I/O模型

  非阻塞I/O模型:我们把一个套接口设置为非阻塞就是告诉内核,当所请求的I/O操作无法完成时,不要将进程睡眠(阻塞),而是返回一个错误。这样我们的I/O操作函数将不断的查询内核看数据是否已经准备好,如果没有准备好,继续测试,直到数据准备好为止。在这个不断测试的过程中,会大量的占用CPU的时间,是极大的浪费
  当一个应用程序像这样对一个非阻塞描述符循环调用recvfrom时,我们称之为轮询(polling)。应用进程连续不断地查询内核,看看某操作是否准备好,这对CPU时间是极大的浪费,但这种模型只是偶尔才遇到,一般是在只专门提供某种功能的系统中才有。
  当用户进程发出read操作时,如果kernel中的数据还没有准备好,那么它并不会block用户进程,而是立刻返回一个error。从用户进程角度讲 ,它发起一个read操作后,并不需要等待,而是马上就得到了一个结果。用户进程判断结果是一个error时,它就知道数据还没有准备好,于是它可以再次发送read操作。一旦kernel中的数据准备好了,并且又再次收到了用户进程的system call,那么它马上就将数据拷贝到了用户内存,然后返回。

所以,nonblocking IO的特点是用户进程需要不断的主动询问kernel数据好了没有,如果数据已经准备好,从内核拷贝到用户空间,否则一直轮询问下去。

5. I/O多路复用模型

  I/O多路复用机制,就是说通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知应用进程进行相应的读写操作。

  Iselect,poll,epoll都是IO多路复用的机制,有些地方也称这种IO方式为event driven IO(事件驱动I/O)。
  当用户进程调用了select,整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
  它的基本原理就是select,poll,epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。select,poll,epoll这个function也会使进程阻塞,但是和阻塞I/O所不同的的,这两个函数可以同时阻塞多个网络连接的I/O操作。而且可以同时对多个读操作,多个写操作的I/O函数进行检测,直到有数据可读或可写时,才真正调用I/O操作函数。 
所以,I/O 多路复用的特点是 整个用户的process其实是一直被block的。只不过第一阶段process是被select这个函数block,而不是被socket IO给block。

6. 信号驱动I/O模型 

  信号驱动 I/O模型:可以用信号,让内核在描述符就绪时发送SIGIO信号通知我们何时可以启动一个IO操作。

  要开启套接字的信号驱动I/O功能,通过sigaction系统调用安装一个信号处理函数。该系统调用将立即返回,我们的进程继续工作,也就是说它没有被阻塞。当数据报准备好读取时,内核就为该进程产生一个SIGIO信号。我们随后既可以在信号处理函数中调用recvfrom读取数据报,并通知主循环数据已经准备好待处理。
  优势:等待数据报到达期间进程不被阻塞。主循环可以继续执行,只要等待来自信号处理函数的通知:既可以是数据已准备好被处理,也可以是数据报已准备好被读取。
所以,信号驱动 I/O模型的特点是 由内核通知我们何时可以启动一个IO操作。

7. 异步I/O模型

  异步I/O模型:告知内核启动某个操作,并让内核在整个操作(包括将内核复制到我们自己的缓冲区)完成后通知我们。

  用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。

  调用aio_read(Posix异步I/O函数以aio_或lio_开头)函数,给内核传递描述字、缓冲区指针、缓冲区大小(与read相同的3个参数)、文件偏移以及通知的方式,然后系统立即返回。我们的进程不阻塞于等待I/0操作的完成。当内核将数据拷贝到缓冲区后,再通知应用程序。

  linux下的asynchronous IO其实用得很少。

所以,异步I/O模型的特点是 由内核通知我们I/O操作何时完成。

8. 阻塞IO vs 非阻塞IO

  blocking:调用blocking IO会一直block对应的进程直到准备数据操作完成。

  non-blocking:在kernel还准备数据的情况下会立刻返回。

  (等待数据阶段)

9. 同步IO vs 异步IO

  在说明synchronous IO和asynchronous IO的区别之前,需要先给出两者的定义。POSIX的定义是这样子的:

- A synchronous I/O operation causes the requesting process to be blocked until that I/O operation completes;
- An asynchronous I/O operation does not cause the requesting process to be blocked;

同步IO:IO操作导致请求进程阻塞,直到IO操作完成;(Blocking IO,Non-blocking IO,IO multiplexing,Singnal Driven IO)

异步IO:IO操作不导致请求进程阻塞;(Asynchronous IO)

(拷贝数据阶段)

  有人会说,non-blocking IO并没有被block啊。这里有个非常“狡猾”的地方,定义中所指的”IO operation”是指真实的IO操作,就是例子中的recvfrom这个system call。non-blocking IO在执行recvfrom这个system call的时候,如果kernel的数据没有准备好,这时候不会block进程。但是,当kernel中数据准备好的时候,recvfrom会将数据从kernel拷贝到用户内存中,这个时候进程是被block了,在这段时间内,进程是被block的。

  而asynchronous IO则不一样,当进程发起IO 操作之后,就直接返回再也不理睬了,直到kernel发送一个信号,告诉进程说IO完成。在这整个过程中,进程完全没有被block。

10. 五种I/O模型对比

 各个IO Model的比较如图所示:(若要提高IO效率,需要将等待的时间降低)

  通过上面的图片,可以发现non-blocking IO和asynchronous IO的区别还是很明显的。在non-blocking IO中,虽然进程大部分时间都不会被block,但是它仍然要求进程去主动的check,并且当数据准备完成以后,也需要进程主动的再次调用recvfrom来将数据拷贝到用户内存。而asynchronous IO则完全不同。它就像是用户进程将整个IO操作交给了他人(kernel)完成,然后他人做完后发信号通知。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动的去拷贝数据。

11. 总结

  1. 阻塞I/O(Blocking I/O):应用程序调用一个IO函数,导致应用程序阻塞,如果数据已经准备好,从内核拷贝到用户空间,否则一直等待下去。

  2. 非阻塞I/O(Non-Blocking I/O): 用户进程需要不断的主动询问kernel数据好了没有,如果数据已经准备好,从内核拷贝到用户空间,否则一直轮询问下去。

  3. I/O多路复用(I/O Multiplexing): 通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知应用进程进行相应的读写操作。select,poll,epoll都是IO多路复用的机制,有些地方也称这种IO方式为event driven IO(事件驱动I/O)。

  4. 信号驱动I/O(Signal Driven I/O):可以用信号,让内核在描述符就绪时发送SIGIO信号通知我们何时可以启动一个IO操作。

  5. 异步I/O(Asychronous I/O): 告知内核启动某个操作,并让内核在整个操作(包括将内核复制到我们自己的缓冲区)完成后通知我们。

摘录网址

I/O模型之一:Unix的五种I/O模型

IO多路复用机制详解

参考Richard Stevens的“UNIX® Network Programming Volume 1, Third Edition: The Sockets Networking ”,6.2节“I/O Models ”

参考《unix网络编程》

参考http://blog.csdn.net/blueboy2000/article/details/4485874

参考http://blog.csdn.net/suxinpingtao51/article/details/46314097

同步与阻塞,异步与非阻塞的区别

阻塞IO、非阻塞IO的区别

ps: 抛弃本文上下文

  同步与异步是对应的,它们是线程之间的关系,两个线程之间要么是同步的,要么是异步的。

  阻塞与非阻塞是对同一个线程来说的,在某个时刻,线程要么处于阻塞,要么处于非阻塞。

  

  阻塞是使用同步机制的结果,非阻塞则是使用异步机制的结果。

  同步IO和异步IO的区别就在于:数据拷贝的时候进程是否阻塞!

  阻塞IO和非阻塞IO的区别就在于:应用程序的调用是否立即返回!

I/O模型系列之二:Unix的五种网络I/O模型的更多相关文章

  1. I/O模型之一:Unix的五种I/O模型

    目录: <I/O模型之一:Unix的五种I/O模型> <I/O模型之二:Linux IO模式及 select.poll.epoll详解> <I/O模型之三:两种高性能 I ...

  2. 2018.5.4 Unix的五种IO模型

    阻塞非阻塞和异步同步 同步和异步关注的是消息通信机制,关注两个对象之间的调用关系. 阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态,关注单一程序. Unix的五种IO模型 以下基于Li ...

  3. Unix下五种IO模型

    http://blog.chinaunix.net/uid-25324849-id-247813.html 1. I/O模型 Unix下共有五种I/O模型 a. 阻塞I/O b. 非阻塞I/O c. ...

  4. Unix下 五种 I/O模型

    Unix下共有五种I/O模型: 1. 阻塞式I/O  2. 非阻塞式I/O  3. I/O复用(select和poll)  4. 信号驱动式I/O(SIGIO)  5. 异步I/O(POSIX的aio ...

  5. 五种网络IO模型以及多路复用IO中select/epoll对比

    下面都是以网络读数据为例 [2阶段网络IO] 第一阶段:等待数据 wait for data 第二阶段:从内核复制数据到用户 copy data from kernel to user 下面是5种网络 ...

  6. Jerry带您了解Restful ABAP Programming模型系列之二:Action和Validation的实现

    相信通过Jerry的前一篇文章 30分钟用Restful ABAP Programming模型开发一个支持增删改查的Fiori应用,想必大家对Restful ABAP Programming模型已经有 ...

  7. Javascript事件模型系列(二)事件的捕获-冒泡机制及事件委托机制

    一.事件的捕获与冒泡 由W3C规定的DOM2标准中,一次事件的完整过程包括三步:捕获→执行目标元素的监听函数→冒泡,在捕获和冒泡阶段,会依次检查途径的每个节点,如果该节点注册了相应的监听函数,则执行监 ...

  8. 分布式缓存技术redis学习系列(二)——详细讲解redis数据结构(内存模型)以及常用命令

    Redis数据类型 与Memcached仅支持简单的key-value结构的数据记录不同,Redis支持的数据类型要丰富得多,常用的数据类型主要有五种:String.List.Hash.Set和Sor ...

  9. 分布式缓存技术redis系列(二)——详细讲解redis数据结构(内存模型)以及常用命令

    https://www.cnblogs.com/hjwublog/p/5639990.html

随机推荐

  1. maven+springMVC(二)

    [目录]

  2. Express NodeJs Web框架 入门笔记

    Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具. 使用 Express 可以快速地搭建一个完整功能的网 ...

  3. linux 大冒险

    本来想搞一个nas系统,结果上来linux的贼船. 本来是看上了deepin深度linux,结果看到排名第一的manjaro 就忍不住手.通过hyper-v虚拟机安装,发现这个所谓的第一不知道第一在哪 ...

  4. Numpy库的学习(四)

    我们今天继续学习一下Numpy库 接着前面几次讲的,Numpy中还有一些标准运算 a = np.arange(3) print(a) print(np.exp(a)) print(np.sqrt(a) ...

  5. Linux(CentOS 7)安装测试mysql5.6服务

    1.rpm -qa | grep mysql,查看原系统中是否有已经安装得mysql. 注:centos7系统在安装完成后,未安装mysql任何版本. 2. rpm -e --nodeps mysql ...

  6. SQL SERVER 2012 AlwaysOn - 操作系统层面 01

    搭建 AlwaysOn 是件非常繁琐的工作,需要从两方面考虑,操作系统层面和数据库层面,AlwaysOn 非常依赖于操作系统,域控,群集,节点等概念: DBA 不但要熟悉数据库也要熟悉操作系统的一些概 ...

  7. Git源代码管理

    一. 分支管理 使用 git 进行源代码管理,一般将某个项目的所有分支分为以下几条主线 1. Master 顾名思义,既然名字叫 Master ,那么该分支就是主分支的意思. master 分支永远是 ...

  8. Django的URL调度

    1.URLconf (URL configuration):(Django版本1.11.20,其它版本可能各有差异.) 在Django中Python后端与前端URL进行交互,是通过一个名为urlcon ...

  9. 【题解】UVA11362 Phone List

    Tags : ​ 排序,字典树 ​ 从短到长排序,逐个插入字典树.若与已有的重复,返回错误信息. #include <iostream> #include <stdio.h> ...

  10. 大神教你如何解决Linux系统80端口被占用

    有Linux在centos下面安装webmail服务遇到80端口被占用的问题,导致无法继续安装,下面详细介绍下Linux如何查看.查找.关闭监听80端口服务以更好的的解决80端口被占用的问题. 一.查 ...