女朋友:不跟我解释清楚 Linux I/O 今晚你就睡沙发吧!

简介: 女朋友:不跟我解释清楚 Linux I/O 今晚你就睡沙发吧!

image-20230103104522331.png
I/O 其实就是 input 和 output(输入输出)

在计算机操作系统中对应数据流的输入与输出,在 Linux 中,既有文件的 I/O,也有网络 I/O

无论是文件 I/O 还是网络 I/O,其传输过程都是类似的

今天我们以文件 I/O 为例,来深入浅出一下 Linux 的 I/O 模型

我们的程序想要打开一个文件,去查看里面的内容,那么就需要将文件内容加载到内存里面,这个过程是一个比较复杂的过程

首先需要通过内核将数据从硬盘中读取出来,然后放到操作系统的内核缓冲区中,然后再将数据拷贝到程序缓冲区,这时候程序才能获取到相应的数据,打开相应的文件

简单来说,无论什么 I/O 模型,其读取过程都会经历下面两个阶段:

  • 将数据放到内核缓冲区(等待数据过程)
  • 将内核缓冲区的数据拷贝(copy)到程序缓冲区(拷贝数据过程)

image-20221212102411349.png
接下来我们来看一下五种 Linux I/O 模型,不然晚上就得睡沙发了捏

阻塞 I/O

阻塞 I/O 称为 Blocking I/O,简称 BIO

在阻塞 I/O 模型里面,当进程发起一个读取文件的请求时(recvfrom 系统调用),如果内核缓冲区没有缓存对应的数据,那么内核就会去读取磁盘,将对应数据放到内核缓冲区,当数据读取完毕后,返回给进程

这便是第一个阶段,在第一阶段中,进程是阻塞的,它干不了任何事,只能乖乖地等内核将数据读取到内核缓冲区

当进程收到内核的响应之后,把内核缓冲区中的数据 copy 一份到程序缓冲区,最后完成读取文件的操作

这便是第二阶段,在第二阶段中,进程也是堵塞的,它只能乖乖地将数据从内核缓冲区 copy 到程序缓冲区

总结:在阻塞 I/O 模型里面,从硬件到内核,从内核到程序空间,都是阻塞的
image-20230103093707517.png

非阻塞 I/O

在非阻塞 I/O 模型中,当进程发起一个读取文件的请求时(recvfrom 系统调用),如果内核缓冲区没有缓存对应的数据,那么内核就会去读取磁盘,将对应数据放到内核缓冲区

但此时进程的请求不是堵塞的,内核在读取磁盘数据的时候会先返回一个错误信息给进程——数据暂时还没准备好,你待会再来试试

于是进程就会不断地向内核发起重试,一直问:数据准备好了没数据准备好了没

当内核读取数据完毕后,就会通知进程:数据已经准备好了,你可以来拿了

于是第一阶段就此结束,在第一阶段里面进程不会在这里干等,而是不断的轮询重试,但也是阻塞的

当进程收到内核的响应之后,把内核缓冲区中的数据 copy 一份到程序缓冲区,最后完成读取文件的操作

于是第二阶段就此结束,在第二阶段里面进程是堵塞的,它只能乖乖地将数据从内核缓冲区 copy 到程序缓冲区

总结:在非阻塞 I/O 模型里面,从硬件到内核,从内核到程序空间,都是阻塞的。但比阻塞 I/O 有进步了一点,并不是站在那里干等,而是时不时跑去问一下内核。即使是无用功,效率多少还是提高了一点的
image-20230103094922065.png

I/O复用

之所以叫复用,是因为在这个模型中进程可以同时操作多个数据流,而不像前面所讲的阻塞 I/O、非阻塞 I/O 同一时间只能操作一个数据流

在 I/O 复用模型中,进程监听多个数据流,然后去不断的轮询,当其中一个数据流有数据之后,内核便会通知进程

UNIX/Linux 下的 select、poll、epoll 就是干这个的(epoll 比 poll、select 效率高,做的事情是一样的)

于是第一阶段就此结束,在第一阶段里面进程会不断地对多个数据流进行轮询重试,但依旧是阻塞的

当收到内核的通知之后,进程就会将数据从内核缓冲区 copy 到 程序缓冲区,最后完成读取文件的操作

于是第二阶段就此结束,在第二阶段里面进程是堵塞的,它只能乖乖地将数据从内核缓冲区 copy 到程序缓冲区

I/O 多路复用中有 select、poll、epoll 函数,select 调用是内核级别的,select轮询相对非阻塞的轮询的区别在于——select 轮询可以监听多个数据流,当其中任何一个数据流的数据准备好了,就能返回成功

总结:

  • I/O 复用模型的第二阶段与阻塞 I/O、非阻塞 I/O 的第二阶段是一致的,但是在第一阶段中,进程能够同时轮询多个数据流,监听多个数据流,其效率有巨大的提升
  • I/O 多路复用是阻塞在select,epoll 这样的系统调用之上,而没有阻塞在真正的 I/O 系统调用如 recvfrom 之上
  • I/O 多路复用在阻塞到 select 阶段时,用户进程是主动等待并调用 select 函数获取数据就绪状态消息,并且其进程状态为阻塞。所以,把IO多路复用归为同步阻塞模式

image-20230103100256062.png

信号驱动 I/O

信号驱动 I/O 可以说是 I/O 模型上的一个里程碑

它与前面三个 I/O 模型的区别在于信号这个词

信号驱动 I/O 在第一阶段,即等待内核将数据从磁盘读取到内核缓冲区这个阶段,进程是不阻塞的,而是设置了一个信号回调,当数据到达内核缓冲区之后,内核调用程序的回调

在第一阶段里面进程是非阻塞的,它可以去干其他事情

当数据到达内核缓存区,进程收到内核的信号之后,进程再将数据从内核缓冲区 copy 到程序缓冲区,最后完成读取文件的操作

第二阶段就此结束,在第二阶段里面进程是堵塞的,它只能乖乖地将数据从内核缓冲区 copy 到程序缓冲区

总结:

  • 虽然说信号驱动 I/O 模型的第二阶段跟前面三个 I/O 模型一样,即进程是阻塞的。但在第一阶段做到了真正的异步
  • 信号驱动 IO 在第一阶段,进程去请求内核读取数据,这时候其不会阻塞,也不会去轮询,而是设置一个信号回调。 当数据完全拷贝到系统内核时,系统发出 SIGIO 信号,通知进程去进行第二阶段,将数据拷贝到程序缓冲区

image-20230103101317820.png

异步 I/O

异步I/O 相比前面四个 I/O 模型,无论是第一阶段还是第二阶段都实现了非阻塞

与信号驱动 I/O 类似,异步 I/O 模型在第一阶段通过信号回调的方式实现了进程的非阻塞

即用户进程进行 aio_read 系统调用之后,无论内核数据是否准备好,都会直接返回给用户进程,然后用户态进程可以去做别的事情

而在第二阶段,进程将数据从内核缓冲区 copy 到程序缓冲区的时候并非阻塞,而是同样设置一个信号回调,当 copy 完成后,进程收到通知,再去执行相应的操作

总结:异步 IO 不仅仅是在第一阶段实现了信号回调,其也在第二阶段实现了信号回调,两个过程都是非阻塞的,从而完全实现了异步 IO 操作
image-20230103101634427.png

总结

我们根据这五种 I/O 模型在第一第二阶段的表现来总结一下:

  • 阻塞 I/O

    • 第一阶段(硬件到系统内核),阻塞
    • 第二阶段(系统内核到程序空间),阻塞
  • 非阻塞 I/O

    • 第一阶段(硬件到系统内核),轮询阻塞
    • 第二阶段(系统内核到程序空间),阻塞
  • I/O 复用

    • 第一阶段(硬件到系统内核),多路轮询阻塞
    • 第二阶段(系统内核到程序空间),阻塞
  • 信号驱动 I/O

    • 第一阶段(硬件到系统内核),信号驱动不阻塞
    • 第二阶段(系统内核到程序空间),阻塞
  • 异步 I/O

    • 第一阶段(硬件到系统内核),信号驱动不阻塞
    • 第二阶段(系统内核到程序空间),信号驱动不阻塞

从上面的 5 种 I/O 模型,我们可以看出,真正实现异步非阻塞的只有异步 IO 这种模型,而其他四种都是同步 I/O

因为在第二阶段:从内核缓冲区复制到程序缓冲区的时候,不可能干其他事情

最后再来简单说说阻塞与非阻塞、同步与异步的区别

阻塞与非阻塞:

  • 阻塞 I/O 会一直 block 对应的进程,直到 I/O 操作完成
  • 非阻塞 I/O 在内核还在准备数据的情况下会立刻返回给进程

同步与异步:

在说明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;

两者区别就在于——同步 I/O 做 I/O 操作(I/O operation)时会将进程阻塞掉,按照这个定义,之前所述的阻塞I/O、非阻塞 I/O,I/O 多路复用都属于同步 I/O

可能这里有人会想:非阻塞 I/O 并没有被 block 啊,请注意上面说的定义,定义中所指的 I/O 操作是指真实的 I/O 操作,就是上面例子中的 recvfrom 这个系统调用

非阻塞 I/O 在第一阶段,也就是执行 recvfrom 这个系统调用的时候,如果内核数据还没有准备好,是不会 block 进程的,但是在第二阶段,如果内核的数据准备好并要 copy 到用户缓冲区中,这个时候进程就会被 block

而异步 I/O 则不一样,它实现了两个阶段都是非阻塞的,当进程发起 I/O 操作之后,就直接返回再也不理睬了,直到内核发送一个信号,告诉进程说 I/O 完成。在这整个过程中,进程完全没有被block

image-20230103103554592.png

相关文章
|
3天前
|
缓存 网络协议 Unix
Linux(UNIX)五种网络I/O模型与IO多路复用
Linux(UNIX)五种网络I/O模型与IO多路复用
116 0
|
7月前
|
域名解析 网络协议 Unix
linux常用命令及解释大全(三)
本篇文章继续介绍了一部分linux常用命令,包括字符设置和文件格式转换,文件系统分析,初始化一个文件系统,备份,光盘,网络这六个部分。linux常用命令及解释大全(三)详情请看正文。
72 2
|
7月前
|
存储 缓存 Linux
百度搜索:蓝易云【如何在Linux系统服务器中测试存储/磁盘I/O性能?】
这些工具可以帮助你测试磁盘的读取和写入性能,并提供各种性能指标和统计数据。请注意,在运行这些测试时,确保没有重要的数据存储在被测试的磁盘上,并谨慎操作以避免对系统和数据造成不必要的影响。
92 0
|
7月前
|
监控 网络协议 Java
I/O多路复用【Linux/网络】(C++实现select、poll和epoll服务器)(上)
I/O多路复用【Linux/网络】(C++实现select、poll和epoll服务器)
121 0
|
3天前
|
缓存 Ubuntu 网络协议
Linux系统编程之文件I/O函数的使用:介绍文件I/O函数的基本概念、用法和实现方式
Linux系统编程之文件I/O函数的使用:介绍文件I/O函数的基本概念、用法和实现方式
32 1
|
3天前
|
存储 缓存 Linux
【linux基础I/O(二)】文件系统讲解以及文件缓冲区的概念
【linux基础I/O(二)】文件系统讲解以及文件缓冲区的概念
|
3天前
|
网络协议 Linux 网络安全
Linux服务器DNS服务器配置实现bind的正向解释和反向解释
Linux服务器DNS服务器配置实现bind的正向解释和反向解释
23 0
|
3天前
|
监控 网络协议 Linux
Linux I/O多路复用深入解析:从select到epoll的演进之路
Linux I/O多路复用深入解析:从select到epoll的演进之路
77 0
|
3天前
|
Linux
Linux系统编程之exec函数簇的使用:剖析exec函数簇的实现原理、参数解释和用法技巧
Linux系统编程之exec函数簇的使用:剖析exec函数簇的实现原理、参数解释和用法技巧
41 0
|
6月前
|
存储 缓存 数据管理
深入理解Linux内核I/O机制:探索文件系统与设备驱动(上)
深入理解Linux内核I/O机制:探索文件系统与设备驱动