文章首发于公众号「陈树义」及个人博客 shuyi.tech,欢迎关注访问。

博主个人独立站点开通啦!欢迎点击访问:https://shuyi.tech

IO 其实就是 Input 和 Output,在操作系统中就对应数据流的输入与输出。这个数据流的两端,可以是文件,也可以是网络的一台主机。但无论是文件,还是网络主机,其传输都是类似的,我们今天就以源头为文件进行说明。

一个文件要从磁盘到我们的内存,需要经过很复杂的操作。首先,需要将数据从硬件读取出来,然后放入操作系统内核缓冲区,之后再将数据拷贝到程序缓冲区,最后应用程序才能读取到这个文件。简单地说,无论什么 IO 模型,其读取过程总会经历下面两个阶段:

  • 等待数据到达内核缓冲区
  • 从内核缓冲区拷贝数据到程序缓冲区

文章首发于公众号「陈树义」及个人博客 shuyi.tech,欢迎关注访问。

而我们 Linux 根据这两个阶段的是否阻塞,分成了 5 个经典的 IO 的模型,分别是:

  • 阻塞 IO 模型
  • 非阻塞 IO 模型
  • IO 复用模型
  • 信号驱动 IO 模型
  • 异步 IO 模型

阻塞 IO 模型

阻塞 IO 称为 Blocking IO,简称 BIO。在阻塞 IO 模型中,当进程发起一个读取文件请求(recvfrom 系统调用)时,如果内核缓存区没有对应的数据,那么它不会立刻恢复,而是去读取磁盘数据,当数据读取完毕后,再返回给进程。此时,第一个阶段完成。在这个阶段进程是阻塞的,因为它要等待内核将数据读取到内核缓冲区。

而当进程收到内核的响应之后,进程再把数据从内核缓冲区复制到程序缓冲区,最后完成文件读取操作。此时,第二个阶段完成。在这个阶段进程也是阻塞的,因为它要将数据从内核缓冲区拷贝到程序缓冲区。

简单地说:在阻塞 IO 模型里,从硬件到系统内核、从系统内核到程序空间,都是阻塞的。

非阻塞 IO 模型

在非阻塞 IO 模型下,当一个请求发起读取文件请求(recvfrom)时,如果内核缓冲区没有数据,那么内核会读取文件数据。但此时请求并不会阻塞,而是返回一个错误信息(EWOULDBLOCK)告诉进程:数据暂时还没准备好,你待会儿再试试。

于是进程就不断地向内核重试,问:数据准备好了没有,数据准备好了没有……当内核准备好数据,进程就会收到对应消息,于是第一阶段就结束了。非阻塞 IO 中的非阻塞说的就是进程不会阻塞在这里,而是会不断重试。

虽然说这样并没有太大用处,反而会使得 CPU 空转,但总比之前有了一点进步。在这个阶段进程并不是阻塞的。当进程得知内核准备好数据之后,其便会将数据从内核缓冲区拷贝到程序缓冲区。这个阶段与阻塞 I/O 模型是完全一样的,同样是会导致进程阻塞。

文章首发于公众号「陈树义」及个人博客 shuyi.tech,欢迎关注访问。

简单地说:在非阻塞 IO 模型里,从硬件到系统内核、从系统内核到程序空间,同样都是阻塞的。但是其比阻塞 IO 争气了一点,并不是站在那里不动,好歹还跑了一下。虽然是在做无用功,但是好歹提高了一丢丢效率。

IO 复用模型

IO 复用之所以叫复用,是因为其能同时操作多个数据流。而前面的 阻塞 IO、非阻塞 IO 同一时间只能操作一个数据流。在 IO 复用模型中,进程监听多个数据流并阻塞,当任何一个数据流有数据之后,其便会收到内核的响应。此时,第一个阶段完成,在这个阶段进程其实是阻塞的。

而当收到内核的响应后,进程便会将数据从内核缓冲区复制到程序缓冲区。这个阶段与上面两个模型一模一样,进程同样阻塞。

简单地说:IO 复用模型在第二阶段与阻塞 IO 和非阻塞 IO 是完全一致的。但是在第一阶段上,其有效率上的巨大提升,其能同时轮询多个数据流,提高了效率。

信号驱动 IO 模型

信号驱动与前面几个模型的不同之处就在与信号这个词。信号驱动 IO 在第一阶段,即数据到达内核缓冲区之前,进程是不阻塞的,而是设置一个信号回调。当数据到达内核缓冲区之后,内核调用程序的回调。通过这种方式,信号驱动 IO 下的进程就可以不阻塞,可以去做其他事情了。

而当进程收到信号,进程再将数据从内核缓冲区复制到程序缓冲区。这个过程与上面几个是完全一样的,同样也是阻塞的。

信号驱动 IO 可以说是 IO 读取的一个里程碑,其真正实现了异步读取数据。信号驱动 IO 其二个阶段,与上面几个是一样的。但是其在第一个阶段做到了真正的异步。信号驱动 IO 在第一阶段,其去请求内核读取数据,这时候其不会阻塞,也不会去寻轮,而是设置一个信号回调。 当数据完全拷贝到系统内核时,系统发出 SIGIO 信号,通知进程去进行第二阶段,将数据拷贝到程序缓冲区。

异步 IO 模型

异步 IO 相比前面几个流程,真正做到了完全非阻塞。无论是在第一阶段,还是在第二阶段都是非阻塞。与信号驱动 IO 类似,异步 IO 模型通过信号回调的方式,在第一个阶段实现了进程的非阻塞。而当数据到达内核缓冲区之后,进程便会收到通知。

而当进程收到通知之后,进程再次将数据从内核缓冲区复制到进程缓冲区,但这时进程并不等待,而是同样设置一个信号回调。当复制完成后,进程收到通知,再进行相应的处理。

异步 IO 与信号驱动 IO 相比,做得更加彻底了!

异步 IO 不仅仅是在第一阶段实现了信号回调,其也在第二阶段实现了信号回调,从而完全实现了异步 IO 操作。

文章首发于公众号「陈树义」及个人博客 shuyi.tech,欢迎关注访问。

总结

我们回顾一下这 5 种 IO 模型:

  • 阻塞 IO 模型:硬件到系统内核,阻塞。系统内核到程序空间,阻塞。
  • 非阻塞 IO 模型:硬件到系统内核,轮询阻塞。系统内核到程序空间,阻塞。
  • 复用 IO 模型:硬件到系统内核,多流轮询阻塞。系统内核到程序空间,阻塞。
  • 信号驱动 IO 模型:硬件到系统内核,信号回调不阻塞。系统内核到程序空间,阻塞。
  • 异步 IO 模型:硬件到系统内核,信号回调不阻塞。系统内核到程序空间,信号回调不阻塞。

从上面的 5 种 IO 模型,我们可以看出,真正实现异步非阻塞的只有异步 IO 这种模型,而其他四种都是同步性 IO。因为在第二阶段:从内核缓冲区复制到进程缓冲区的时候,不可能干其他事情。

好了,关于 Linux IO 模型的分享,今天就聊到这儿。

谢谢大家的阅读。如果文章对你有帮助,欢迎评论转发点赞三连,我们下次见~

其实 Linux IO 模型没那么难的更多相关文章

  1. Linux IO模型和网络编程模型

    术语概念描述: IO有内存IO.网络IO和磁盘IO三种,通常我们说的IO指的是后两者. 阻塞和非阻塞,是函数/方法的实现方式,即在数据就绪之前是立刻返回还是等待. 以文件IO为例,一个IO读过程是文件 ...

  2. 7层网络以及5种Linux IO模型以及相应IO基础

    一.七层网络模型 OSI是Open System Interconnection的缩写,意为开放式系统互联.国际标准化组织(ISO)制定了OSI模型,该模型定义了不同计算机互联的标准,它是一个七层的. ...

  3. Linux IO模型

    1. Linux IO 模型矩阵 2. 同步阻塞IO 3. 同步非阻塞IO 4. 异步阻塞IO 5. 异步非阻塞IO

  4. Linux IO模型(同步异步阻塞非阻塞等)的几篇好文章

    聊聊同步.异步.阻塞与非阻塞聊聊Linux 五种IO模型聊聊IO多路复用之select.poll.epoll详解 ​

  5. Linux IO 模型

    Linux 中主要有五种IO模式:阻塞IO, 非阻塞IO, IO 多路复用,信号驱动IO和异步IO; 如果从同步非同步,阻塞非阻塞角度来看,又可以分为:同步阻塞IO, 同步非阻塞IO,异步阻塞IO和异 ...

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

    本文转载自: http://mp.weixin.qq.com/s?__biz=MzAxODI5ODMwOA==&mid=2666538919&idx=1&sn=6013c451 ...

  7. Socket-IO 系列(一)Linux 网络 IO 模型

    Socket-IO 系列(一)Linux 网络 IO 模型 一.基本概念 在正式开始讲 Linux IO 模型前,先介绍 5 个基本概念. 1.1 用户空间与内核空间 现在操作系统都是采用虚拟存储器, ...

  8. Linux 中的五种 IO 模型

    Linux 中的五种 IO 模型 在正式开始讲Linux IO模型前,比如:同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一 ...

  9. 深入理解JAVA I/O系列六:Linux中的IO模型

    IO模型 linux系统IO分为内核准备数据和将数据从内核拷贝到用户空间两个阶段. 这张图大致描述了数据从外部磁盘向运行中程序的内存中移动的过程. 用户空间.内核空间 现在操作系统都是采用虚拟存储器, ...

随机推荐

  1. Java初始化数据域的途径

    Java调用构造器的具体处理步骤: 1.所有数据域被初始化为默认值(0,false或null); 2.按照在类声明中出现的次序,依次执行所有域的初始化语句和初始化块: 3.如果构造器第一行调用了第二个 ...

  2. CAS的理解

    CAS(CompareAndSweep)工作方式 ​ CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被 ...

  3. 15.Git

    1.Git介绍 1.1版本控制(理解) 无论是代码编写,还是文档编写,我们都会遇到对文档内容反复修改的情况 1.2开发中存在的问题(理解) 程序员小明负责的模块就要完成了,就在即将提交发布之前的一瞬间 ...

  4. GIT·版本回退的指令

    阅文时长 | 0.46分钟 字数统计 | 499.2字符 主要内容 | 1.引言&背景 2.指令集合&示例 3.声明与参考资料 『GIT·版本回退的指令』 编写人 | SCscHero ...

  5. 【转载】CentOS 7自动以root身份登录gnome桌面 操作系统开机后自动登录到桌面 跳过GDM

    CentOS 7自动以root身份登录gnome桌面 ################### #cd /etc/gdm ]# cat custom.conf# GDM configuration st ...

  6. 016.Python闭包函数以及locals和globals

    一 闭包函数 内函数使用了外函数的局部变量,并且外函数把内函数返回出来的过程叫做闭包,这个内函数叫做闭包函数 1.1 闭包函数语法 def outer(): a = 5 def inner(): pr ...

  7. Docker 的神秘世界

    引言 上图就是 Docker 网站的首页,看了这简短的解释,相信你还是不知道它是何方神圣. 讲个故事 为了更好的理解 Docker 是什么,先来讲个故事: 我需要盖一个房子,于是我搬石头.砍木头.画图 ...

  8. MyBatis 数据源的原理和机制

    回顾JDBC JDBC访问数据库流程 加载驱动 获取Connection连接对象(消耗性能) 获取PrepareStatement对象 执行SQL语句 获取结果集 关闭Connection连接对象 存 ...

  9. Python数学建模-01.新手必读

    Python 完全可以满足数学建模的需要. Python 是数学建模的最佳选择之一,而且在其它工作中也无所不能. 『Python 数学建模 @ Youcans』带你从数模小白成为国赛达人. 1. 数学 ...

  10. 201871030129-魏琦 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    项目 内容 课程班级博客链接 班级博客 这个作业要求链接 作业链接 我的课程学习目标 (1)掌握Github协作开发程序的操作方法:(2)理解并掌握代码风格规范.代码设计规范.代码复审.结对编程概念: ...