IO模型

用一幅图表示所支持的I/O模型

纵向维度是“阻塞(Blocking)”、“非阻塞(Non-blocking)”;横向维度是“同步”、“异步”。总结起来是四种模型 同步阻塞、同步非阻塞;异步阻塞、异步非阻塞 。《Unix网络编程》中划分出了“第五种”模型——“信号驱动式IO”其实属于异步阻塞类型,这种模型的通知方式有多种多样后面展开说明。

同步/异步、阻塞/非阻塞

从内核角度看I/O操作分为两步:用户层API调用;内核层完成系统调用(发起I/O请求)。所以“异步/同步”的是指API调用;“阻塞/非阻塞”是指内核完成I/O调用的模式。用一幅图表示更加明显

同步是指函数完成之前会一直等待; 阻塞 是指系统调用的时候进程会被设置为Sleep状态直到等待的事件发生(比如有新的数据)。明白这一点之后再看这五种模型相信就会清晰很多,我们挨个分析:

同步阻塞

这种模型最为常见,用户空间调用API( read 、 write )会转化成一个I/O请求,一直等到I/O请求完成API调用才会完成。这意味着: 在API调用期间用户程序是同步的的;这个API调用会导致系统以阻塞的模式执行I/O,如果此时没有数据则一直“等待”(放弃CPU主动挂起——Sleep状态) (注意,对于硬盘来说是不会出现阻塞的,无论是什么时候读它总是有数据。常见的阻塞设备是终端、网卡之类的)。

以 read 为例子,它由三个参数组成,第一个函数是文件描述符;第二个是 应用缓冲 ;第三个参数是需要读取的字节数。经过系统调用会以阻塞模式执行I/O,I/O模块读取数据后会放入到PageCache中;最后一步是把数据从PageCache复制到 应用缓冲 。如果I/O请求无法得到满足——没有数据,则主动让出CPU直到 有数据 (注意,即便系统调用让出CPU也未必真的就让出。read函数是同步的,所以CPU还是会被用户空间代码占用)。

同步非阻塞

这种模式通过调用 read 、 write 的时候指定 O_NONBLOCK 参数。和“同步阻塞”模式的区别在于系统调用的时候它是以非阻塞的方式执行,无论是否有数据都会立即返回。 以 read 为例,如果成功读取到数据它返回读取到的字节数;如果此时没有数据则返回-1,同时设置errno为EAGAIN(或者EWOULDBLOCK,二者相同)。所以这种模式下我们一般会用一个“循环”不停的尝试读取数据,处理数据。

异步阻塞

同步模型最主要的问题是占用CPU, 阻塞I/O会主动让出CPU但是用户空间的系统调用还是不会返回依然耗费CPU;非阻塞I/O必须不停的“轮询”不断尝试读取数据(会耗费更多CPU更加低效)。如果仔细分析同步模型霸占CPU的原因不难得出结论——都是在等待数据到来。异步模式正是意识到这一点所以把I/O读取细化为 订阅I/O事件,实际I/O读写,在“订阅I/O事件”事件部分会主动让出CPU直到事件发生 。异步模式下的I/O函数和同步模式下的I/O函数是一样的(都是 read 、 write )唯一的区别是异步模式 “读”必有数据 而同步模式则未必。 常见的异步阻塞函数包括 select , poll , epoll ,这些函数的用法需要花费相当大的篇幅介绍而这篇文章我想集中精力介绍“I/O模型”。以 select 为例我们看一下大致原理

异步模式下我们的API调用分为两步,第一步是通过 select 订阅读写事件 这个函数会主动让出CPU直到事件发生(设置为Sleep状态,等待事件发生) ;select一旦返回就证明可以开始读了所以第二部是通过 read 读取数据( “读”必有数据 )。

异步阻塞模型之信号驱动

“完美主义者”看了上面的 select 之后会有点不爽——我还要“等待”读写事件(即便 select 会主动让出CPU),能不能有读写事件的时候主动通知我啊?。借助“信号”机制我们可以实现这个,但是这并不完美而且有点弄巧成拙的意思。 具体用法:通过 fcntl 函数设置一个 F_GETFL|O_ASYNC ( 曾经信号驱动I/O也叫“异步I/O”所以才有 O_ASYNC 的说法),当有I/O时间的时候操作系统会触发 SIGIO 信号。在程序里只需要绑定 SIGIO 信号的处理函数就可以了。但是这里有个问题—— 信号处理函数由哪个进程执行呢? ,答案是:“属主”进程。操作系统只负责参数信号而实际的信号处理函数必须由用户空间的进程实现。(这就是设置 F_SETOWN 为当前进程PID的原因) 信号驱动性能要比 select 、 poll 高(避免文件描述符的复制)但是缺点是致命的——*Linux中信号队列是有限制的如果操过这个数字问题就完全无法读取数据。

异步非阻塞

这种模型是最“省事”的模型,系统调用完成之后就只要坐等数据就可以了。是不是特别爽?其实不然,问题出在实现上。Linux上的AIO两个实现版本,POSIX的实现最烂(蓝色巨人的锅)性能很差而且是基于“事件驱动”还会出现“信号队列不足”的问题(所以它就偷偷的创建线程,导致线程也不可控了);一个是Linux自己实现的(redhat贡献)Native AIO。Native AIO主要涉及到的两个函数io_submit 设置需要I/O动作(读、写,数据大小,应用缓冲区等); io_getevents 等待I/O动作完成。没错,即便你的整个I/O行为是非阻塞的还是需要有一个办法知道数据是否读取/写入成功。

注意图中,内核不再为I/O分配PageCache,所有的数据必须有用户自己读取到应用缓冲中维护。所以AIO一定是和“直接I/O”配合使用。 AIO针对网卡设备的意义不大,首先它的实现本质上和epoll差不多;其次它在Linux中的作用更多的是用于磁盘I/O(异步非阻塞可以不用多线程就造成大量的I/O请求便于I/O模块“合并”优化会提高整体I/O的吞吐率——而且对CPU开销比较少)。 在Nginx中用了一个技巧,可以实现AIO和epoll联动,AIO读取到数据后触发epoll发送数据。(这个特性是非常尴尬的,如果是磁盘文件完全可以用sendfile搞定)。

Direct I/O和Buffered I/O

Linux在进行I/O操作的时候会先把数据放到PageCache中然后通过“内存映射”的方式返回给应用程序,这样做的好处是可以预读数据也能在多个进程读取相同数据的时候起到Cache的作用。应用程序不能直接使用PageCache中的数据,通常是复制到一块“用户空间”的内存中再使用。
● Direct I/O是指数据不落在PageCache,直接从设备读取到数据后放到用户空间中
● Buffered I/O是指数据竞购PageCache
同步I/O只能使用Buffered I/O;异步阻塞I/O可以Buffered I/O也可以使用Direct I/O;异步非阻塞I/O只能使用Direct I/O

Zero Copy

考虑从磁盘读取文件经过网卡发送出去,会有 四次内存复制 :1. DMA会复制磁盘数据到内核空间,2. 应用程序复制内核空间的数据到用户空间;3. 应用程序用户空间的数据复制到Socket缓冲(内核空间);4. 协议栈把数据复制到网卡的中发送。 简单来说Zero Copy就是 节省这个过程中的内存复制次数 。有几种做法:
● Direct I/O直接把磁盘数据复制到内核空间; 但是Direct I/O没有办法直接把数据放到网卡中——必须要经过协议栈 。所以可以节省一次内存复制;
● sendfile,磁盘数据通过DMA读取到内核空间后直接交给TCP/IP协议栈;真正的不需要内存复制;
除此之外还可以利用 splice 、 mmap 做一些优化,根据不同的设备需要采用不同的方式此处不再展开。


博客学习转载,非原创。

Unix网络编程5种IO模型相关推荐

  1. 网络编程五种IO模型的形象比喻(老陈收信)

    网摘录如下比喻,实在生动贴切..... select模型  WSAAsyncSelect模型  WSAEventSelect模型  Overlapped I/O 事件通知模型  Overlapped ...

  2. 网络编程五种IO模型之epoll模型

    // epoll2.cpp : 定义控制台应用程序的入口点. //#include <stdio.h> #include <sys/epoll.h> #include < ...

  3. 网络编程五种IO模型之poll模型

    // poll_impl.cpp : 定义控制台应用程序的入口点. //#include "stdafx.h"#include <unistd.h> #include ...

  4. 说说基于网络的五种IO模型

    # django不是一个异步框架 # tornado是异步的web框架# 处理每秒大量的请求# 个人理解的IO:就是应用层与内核驱动层的交互,这个过程无论从应用层到内核中,还是驱动层等待硬件层的数据, ...

  5. java基础巩固-宇宙第一AiYWM:为了维持生计,四大基础之OS_Part_2整起~IO们那些事【包括五种IO模型:(BIO、NIO、IO多路复用、信号驱动、AIO);零拷贝、事件处理及并发等模型】

    PART0.前情提要: 通常用户进程的一个完整的IO分为两个阶段(IO有内存IO.网络IO和磁盘IO三种,通常我们说的IO指的是后两者!):[操作系统和驱动程序运行在内核空间,应用程序运行在用户空间, ...

  6. Linux io模型及函数调用,Linux 网络编程的5种IO模型:信号驱动IO模型

    Linux 网络编程的5种IO模型:信号驱动IO模型 背景 这一讲我们来看 信号驱动IO 模型. 介绍 情景引入: 在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个 ...

  7. 网络编程的5种IO模型

    五种IO模型 一. 五种IO模型 ①. 同步阻塞I/O(BIO) ②. 同步非阻塞I/O(NIO) ③. IO多路复用 ④. 信号驱动IO(SIGIO) ⑤. 异步IO(AIO) 一. 五种IO模型 ...

  8. Linux/Unix五种IO模型

    文章目录 引入 操作系统的内核态和用户态 文件描述符fd IO操作过程: 阻塞和非阻塞 同步和异步 同步IO和异步IO 五种IO模型 1.(同步)阻塞IO模型 2.(同步)非阻塞IO模型 3.IO多路 ...

  9. Linux 下的五种 IO 模型

    Linux 下的五种 IO 模型 来源:decaywood's Blog 概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2 ...

  10. 聊聊 Linux 中的五种 IO 模型

    聊聊 Linux 中的五种 IO 模型 2016/04/21 · IT技术 · 8 评论 · iO, 同步, 异步, 阻塞, 非阻塞 分享到:0 本文作者: 伯乐在线 - 陶邦仁 .未经作者许可,禁止 ...

最新文章

  1. DNA sequencing technologies: 2006–2016
  2. java 环境变量的涵义
  3. 那些年我们一起玩DIY总结出的经验——网络篇
  4. 点是否在面内算法(Point-In-Polygon Algorithm)
  5. SQL Server 2019安装教程
  6. 「Newcoder练习赛40D」小A与最大子段和
  7. 7步让你get首个数据科学实习
  8. 蓝奏云批量下载v0.3修复版
  9. 怎样学好c语言程序设计这门,初学C语言程序设计的基本方法和技巧
  10. httpd-2.2部署Discuz!论坛系统、wordpress博客系统和phpMyAdmin程序
  11. PTA 程序设计-一帮一(C语言)
  12. 揭秘淘宝286亿海量图片存储与处理架构,海量小文件存储的解决方案
  13. 《鬼武者3》全攻略宝典
  14. ps:消除锯齿和羽化
  15. iphone6s html5没声音,iphone6S来电没声音怎么回事?解决iphone来电没声音的方法
  16. java 将set转成数组,Java程序将Set转换为数组
  17. 图片转成base64格式上传至数据库
  18. 一个barcode 多个 sku号_亚马逊SKU是什么?有什么作用?
  19. 移动硬盘无法弹出,显示被进程占用(system占用)
  20. ElasticSearch、上架与检索

热门文章

  1. 华为手机线刷工具_手机刷机、救砖教程
  2. c 中空格的asc码表_ascii码表由小到大空格字符
  3. 《Adobe Flash CS4中文版经典教程》——1 FLASH CS4快速入门1.1 启动Flash并打开文件...
  4. 2022_天勤数据结构高分笔记_第二章_算法
  5. html作业本,连作业本都不用买了!Word做作业本竟这么简单
  6. 值得每个人看的一篇文章——沉没成本和赌徒黑洞理论(Matlab代码实现)
  7. 数据库系统工程师学习记录(计算机系统知识)
  8. 1《游戏脚本高级编程》之命令脚本的随想
  9. 对抗机器学习—— 迭代FGSM
  10. OpenSesame:一个能够攻击fixed-pin设备的工具