原文出处:http://miaoo.in/talk-about-unix-io-model.html

在实际应用中,数据操作通常分为输入和输出,那么以输入为例,在操作系统中,一个数据的输入通常分为以下两个过程:

a. 等待数据准备好.
b. 将准备好的数据从内核拷贝到用户空间.

下面我们将会分别讨论 I/O 模型中的两个大类,即 同步 I/O 与 异步 I/O。

1. 同步 I/O

同步与异步 I/O 的最大不同,就是在在进行数据复制时(即过程 b ),所有的同步 I/O 模型均会发生阻塞。进一步来看,又可以根据在等待数据准备好时( 过程 a )是否发生阻塞,将同步 I/O 分为:

  • 阻塞 I/O ( blocking I/O ). 其在过程 a 与 过程 b 中均会阻塞。
  • 非阻塞 I/O ( non-blocking I/O ).  过程 a 不阻塞, 过程 b 阻塞。在过程 a 阶段若无数据准备好,则内核立即返回 EWOULDBLOCK 错误 (通过设置 errno),用户进程立即返回因而不会发生阻塞。此时,用户进程可以不断的通过轮询( polling )的方式查询数据是否准备好。一旦数据准备就绪, 进程便会进入阻塞模式(即阻塞于过程 b ),进行数据的拷贝直至完成。
  • I/O 复用( I/O multiplexing, event-driven ).  I/O 复用有时又被称为 事件驱动 I/O, 它的最大优势在于,我们可以将感兴趣的多个I/O事件(更精确的说,应该是 I/O 所对应的文件描述符)注册到 select/poll/epoll/kqueue 之中某一个系统调用上(很多时候,这些系统调用又被称为多路复用器。假设此时我们选择了 select() )。此后,调用进程会阻塞在 select() 系统调用之上(而不是阻塞在真正的 I/O 系统调用(如 read(), write() 等)上)。select() 会负责监视所有已注册的 I/O 事件,一旦有任意一个事件的数据准备好,那么 select() 会立即返回,此时我们的用户进程便能够进行数据的复制操作(过程 b )。总而言之,I/O 复用的优点就在于可以同时等待多个I/O事件;而缺点是会进行两次系统调用(一次 select(), 一次 read() )。

通过上面的讨论可以清楚的看到,同步 I/O 总会有阻塞的过程,这就是“同步”最本质的特征。

2.异步 I/O

如前文所说,异步 I/O 的最大特点在于在过程 a 和过程 b 中, 用户进程均不阻塞。 用户进程告知内核启动某一 I/O 操作, 并让内核全权代为执行(包括等待数据及拷贝数据至用户空间),此后用户进程可以立即执行其它的任何操作。等到所有 I/O 过程执行完成后, 内核会通知用户程。由此可见,在整个过程中,用户进程均不阻塞。

以上谈到了 Unix 系统当中 I/O 操作的具体执行方式。在此基础之上, 我们介绍两种常见的 I/O 事件处理模型。事件处理模型的意义在于我们从更宏观的角度来看待实际应用中如何来处理 I/O 事件。我们还是以一个读操作( read() )为例, 根据 I/O 操作是基于同步或异步,分别介绍如下两种模型:

  • Reactor 模式( event loop ) . 基于同步 I/O
  1. 将要读的文件描述符注册到多路复用器中(如 select(), poll(), epoll() )。
  2. 调用进程阻塞在多路复用器上,其等待已注册的任意一个 I/O 事件发生。
  3. 一旦事件发生(即文件描述符变为可读, 多路复用器返回), 将调用用户提供的事件处理函数( event handler)进行实际的 I/O 复制操作。
  4. 读取完成后,事件处理函数可以对数据进行进一步的处理。
  • Proactor 模式. 基于异步 I/O
  1. 用户进程启动一个异步读文件操作, 同时将该操作注册到多路复用器上。多路复用器并不关心文件是否可读,而只关心该异步操作是否完成。
  2. 整个异步读文件操作由内核完成,用户进程不需要关心。多路复用器阻塞以等待某个完成通知的到达。
  3. 当内核完成了整个读文件操作 – 即数据已经准备好,并已由内核复制到了用户事先提供的缓冲区后 – 通知多路复用器读操作已完成。
  4. 多路复用器再调用相应的事件处理函数( event handler )处理位于用户缓冲区的数据。

由此我们可以看到 Reactor 与 Proactor 最大的区别在于数据准备好后,是由谁来将这些数据复制到用户空间中的缓存区之中。Reactor 由于调用的是同步 I/O , 所以当多路复用器由于数据准备好而返回之后,将会由用户的事件处理函数自行将数据复制到用户缓冲区中, 而 Proactor 由于调用的是异步 I/O ,  因此等待及复制数据均由内核完成,用户进程只需要等待内核的完成通知,此后由事件处理函数对已在缓冲区中的数据进行进一步的处理。

由于 Proactor 模型需要操作系统提供异步 I/O 的支持,要求较高,故基于上面所描述的思想, 我们可以用 Reactor 模型来模拟 Proactor (只需要用户额外提供用户缓冲区来存放读取出的数据)。简单来说,就是由多路复用器来代替用户进程来完成实际的 I/O 复制操作。

在 Reactor 模型的第 3 步中,当某个文件描述符可读使得多路复用器返回之后,多路复用器执行一个非阻塞读操作, 将数据从内核读至用户提供的缓冲区中,此操作完成后通知(调用)对应的事件处理函数,告知其 I/O 操作已完成。 这样一来,我们就可以在各种系统中(无论支持异步 I/O 与否)均对外提供统一的 Proactor 模型接口,而对用户隐藏其后的具体实现细节。

参考资料

1. < Unix network programming >, Chapter 6.

2. Comparing Two High-Performance I/O Design Pattern

PUBLISHED: June 8, 2013
FILED UNDER: Linux计算机理论

TAGS: blocking : Event-driven : I/O : linux : non-blocking : Unix

浅谈 Unix I/O 模型的更多相关文章

  1. 浅谈Unix I/O模型

    关于I/O模型的文章比较多,参考多篇后理解上仍然不太满意,终需自己整理一次,也是编写高吞吐量高性能网络接口模块的基础.这里所说的主要针对网络I/O,近几年面对越来越大的用户请求量,如何优化这些步骤直接 ...

  2. 浅谈 unix, linux, ios, android 区别和联系

    浅谈 unix, linux, ios, android 区别和联系 网上的答案并不是很好,便从网上整理的相对专业的问答,本人很菜,大佬勿喷 UNIX 和 Linux   UNIX 操作系统(尤尼斯) ...

  3. 浅谈Java的内存模型以及交互

    本文的内存模型只写虚拟机内存模型,物理机的不予描述. Java内存模型 在Java中,虚拟机将运行时区域分成6中,如下图:              程序计数器:用来记录当前线程执行到哪一步操作.在多 ...

  4. 转:浅谈UNIX下Apache的MPM及httpd.conf配置文件中相关参数配置

    为什么要并发处理 以Apache为代表的web服务器中,如果不支持并发,则在一个客户端连接的时候,如果该客户端的任务没有处理完,其他连接的客户端将会一直处于等待状态,这事不可想象的,好像没有为什么要不 ...

  5. 浅谈 css3 box盒子模型以及box-flex的使用

    display:box;box-flex是css3新添加的盒子模型属性,它的出现可以解决我们通过N多结构.css实现的布局方式.经典的一个布局应用就是布局的垂直等高.水平均分.按比例划分.   一.使 ...

  6. 浅谈异步IO各模型优缺点

    本文只讨论OverLapped I/O的三种异步模型及完成端口,像select.SWASelect不作讨论,讨论顺序从劣到优,方便于循序渐进地对比,更容易区分各模型之间的差别. 1. OverLapp ...

  7. 浅谈OSI七层模型及ICP/IP四层模型

    1.OSI七层模型的概念 在网络历史的早期,国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)共同出版了开放系统互联的七层参考模型. 一台计算机操作系统中的网络过程包括从应用请求(在协议栈 ...

  8. 【转】从Mac/OS和iOS开放源码浅谈UNIX家谱

    阅读数:1245 苹果公司在各类开源项目中长期贡献着自己的力量,但其UNIX系统技术一直都属于闭源阵营(这一点可以从NUX OS阵营和家谱图中得到答案).然而,以封闭闻名的苹果公司,2017年国庆期间 ...

  9. 【转】浅谈Node.js单线程模型

    Node.js采用 事件驱动 和 异步I/O 的方式,实现了一个单线程.高并发的运行时环境,而单线程就意味着同一时间只能做一件事,那么Node.js如何利用单线程来实现高并发和异步I/O?本文将围绕这 ...

随机推荐

  1. 给公司服务器装web服务器,邮件服务器——安装SecureCRT

    系统用centos5.9 首先在window上安装SecureCRT终端 1:首先验证安装secureCRT的本地机和linux服务器能否ping的通: 2:判断linux 服务端是否安装了ssh 若 ...

  2. bootstrap阶段测验【答案】

    <!DOCTYPE html><html> <head> <meta charset="utf-8" /> <title> ...

  3. Excel函数vlookup

    最近整理业务文档,需要用到excel,按照教程,操作了20来分钟,却得不到结果. 看了视频,才知道,vlookup仅限关联选中区域的第一列关联,把要关联的行拷贝到第一列,解决. https://www ...

  4. CSS 基础 例子 盒子模型及外边距塌陷

    我们通常设置的宽度和高度,是指盒子模型中内容(content)的宽度和高度.元素的高度,还要加上上下padding和上下border,元素整个盒子的高度还要加上上下margin:宽度类似计算. 注意: ...

  5. 配置Info.plist (设置状态栏样式、自定义定位时系统弹出的提示语、配置3DTouch应用快捷菜单)

    一.概述 iOS中很多功能需要配置Info.plist才能实现,如设置后台运行.支持打开的文件类型.自定义访问隐私内容时弹出的提示等.了解Info.plist中各字段及其含义,可以访问苹果开发网站相关 ...

  6. Windows核心编程:第8章 用户模式下的线程同步

    Github https://github.com/gongluck/Windows-Core-Program.git //第8章 用户模式下的线程同步.cpp: 定义应用程序的入口点. // #in ...

  7. Windows的cmd窗口显示utf8字符

    用XeLaTeX的时候,查字体需要用fc-list命令,XeLaTeX用的都是utf编码,所以fc-list输出的字体信息也是utf编码.因此需要把cmd窗口也改成utf8编码才能看到这些字体信息.U ...

  8. C# winfrom 写的一个搜索助手,可以按照标题和内容搜索,支持doc,xls,ppt,pdf,txt等格式的文件搜索

    C# winfrom 写的一个搜索助手,可以按照标题和内容搜索,指定目录后,遍历搜索文件和子目,现在只写了支持.DOC.DOCX.XLS.XLSX.PPT.PPTX.PDF.HTML.HTM.TXT等 ...

  9. C#之简易计算器设计

    在学完了C#的方法和数据类型之后,写了一个简易的计算器的界面.本次界面具备加减乘除求余等五项运算.不过存在一点缺陷就是无法判断输入数据的类型,是整数还是小数,由于目前所学知识有限,等学到以后再进行完善 ...

  10. EF架构获取数据时报错:The ObjectContext instance has been disposed and can no longer be used for operations that require a connection. Do you want to correct the value?

    场景: EF底层,获取完主表,点击按钮,添加主表,字表内容时,报以上错误 解决方案: 在EF文件的空白处右键--属性,将“应用延迟加载”,改为False