I/O 其实就是 input 和 output(输入输出)
在计算机操作系统中对应数据流的输入与输出,在 Linux 中,既有文件的 I/O,也有网络 I/O
无论是文件 I/O 还是网络 I/O,其传输过程都是类似的
今天我们以文件 I/O 为例,来深入浅出一下 Linux 的 I/O 模型
我们的程序想要打开一个文件,去查看里面的内容,那么就需要将文件内容加载到内存里面,这个过程是一个比较复杂的过程
首先需要通过内核将数据从硬盘中读取出来,然后放到操作系统的内核缓冲区中,然后再将数据拷贝到程序缓冲区,这时候程序才能获取到相应的数据,打开相应的文件
简单来说,无论什么 I/O 模型,其读取过程都会经历下面两个阶段:
- 将数据放到内核缓冲区(等待数据过程)
- 将内核缓冲区的数据拷贝(copy)到程序缓冲区(拷贝数据过程)
上面两个阶段完成之后,进程才能够对数据进行操作(读 or 写)
为了让大家能够更好的理解 Linux I/O 模型,咸鱼用囤了一个星期的臭衣服来作为例子(主要是懒)
一个轻松惬意的周六下午,咸鱼看着满满一篮子的臭衣服,痛定思痛,决定今天一定要把这堆衣服洗了
但是咸鱼家的洗衣机比较老旧,别人家的洗衣机都是洗涤甩干一条龙的,咸鱼家的洗衣机只能先洗涤,等洗涤完毕后咸鱼再去按甩干按钮进行衣服甩干(太惨了)
那么就将洗衣服可以分为两个阶段:
- 按下洗涤按钮,洗衣机对衣服进行洗涤
- 按下甩干按钮,洗衣机对衣服进行甩干
以上两个阶段均完成了之后,咸鱼才能把衣服拿去晾晒
阻塞 I/O
咸鱼在按下了洗衣机的洗涤按钮之后,就拿个小板凳在旁边干等着,在洗涤完衣服之前咸鱼啥事都不能干,只能乖乖地等洗衣机洗涤衣服
当洗衣机洗完衣服之后,咸鱼就按下甩干按钮,然后依旧坐在小板凳上干等着,直到洗衣机甩干好衣服为止
以上这两个阶段(洗涤和甩干阶段),咸鱼都处在一个阻塞的状态,他啥也干不了,只能乖乖地等洗衣机工作完
总结:
在阻塞 I/O 模型里面,将数据放到内核缓冲区(等待数据过程)以及将内核缓冲区的数据拷贝(copy)到程序缓冲区(拷贝数据过程),进程都是阻塞的
非阻塞 I/O
跟第一次不一样的是,咸鱼按下了洗衣机的洗涤按钮之后,他会不断地去打开洗衣机盖子,去看衣服洗好了没有
等洗衣机洗好了衣服之后,咸鱼按下洗衣机的甩干按钮,然后坐在小板凳上干等着,直到洗衣机甩干好衣服为止
以上这两个阶段(洗涤和甩干阶段),咸鱼都处在一个阻塞的状态,他啥也干不了,但是在第一阶段(洗涤阶段),咸鱼并没有干等着,而是不断地去查看洗衣机的状态——是否洗好衣服了
总结:
在非阻塞 I/O 模型里面,将数据放到内核缓冲区(等待数据过程)以及将内核缓冲区的数据拷贝(copy)到程序缓冲区(拷贝数据过程),都是阻塞的。
但比阻塞 I/O 有进步了一点,进程并不是站在那里干等,而是时不时跑去问一下内核。即使是无用功,效率多少还是提高了一点的
I/O复用
这一天,邻居家里有事外出了,但邻居也在洗衣服,于是邻居就拜托咸鱼帮忙看一下洗衣机
邻居家的洗衣机跟咸鱼家的洗衣机一样老旧,同样需要先洗涤后甩干
这个时候咸鱼就需要去不断地来回跑,先去看看自己家的洗衣机洗好衣服了没,然后再去看看邻居家洗衣机洗好衣服了没,接着再去看看自己家洗衣机洗好衣服了没
循环往复,直到看到某一台洗衣机完成洗涤
当咸鱼看到某一台洗衣机完成洗涤之后,就需要按下甩干按钮然后乖乖等衣服甩干
在洗涤阶段里面,咸鱼会不断地对洗衣机进行轮询查看,但依旧是阻塞的,因为咸鱼干不了其他事
在甩干阶段里,也是堵塞的,咸鱼只能乖乖地等洗衣机将衣服甩干
总结:
I/O复用模型的第二阶段与阻塞 I/O、非阻塞 I/O 的第二阶段是一致的(进程是堵塞的只能乖乖地将数据从内核缓冲区 copy 到程序缓冲区)
但是在第一阶段中,进程能够同时轮询多个数据流,监听多个数据流,其效率有巨大的提升
信号驱动 I/O
咸鱼发现,在小板凳上干等着多浪费时间啊,俗话说浪费时间无异于自杀,咸鱼决定在洗衣机洗涤阶段去干其他家务活,当洗衣机洗涤完毕后,会发出滴滴的声音,咸鱼听到这个声音之后就回来对衣服甩干
于是在洗涤阶段,咸鱼再也不用坐在小板凳上干等着,而是去拖地、烧水(干其他事)
当洗衣机洗涤完毕后,发出滴滴声音(信号),咸鱼听到这个声音之后就回来然后对衣服进行甩干
但是在甩干阶段咸鱼还是需要坐在小板凳上乖乖地等着
总结:
虽然说信号驱动 I/O 模型的第二阶段跟前面三个 I/O 模型一样,即进程是阻塞的。但在第一阶段做到了真正的异步
信号驱动 IO 在第一阶段,进程去请求内核读取数据,这时候其不会阻塞,也不会去轮询,而是设置一个信号回调。 当数据完全拷贝到系统内核时,系统发出 SIGIO 信号,通知进程去进行第二阶段,将数据拷贝到程序缓冲区
异步 I/O
聪明的咸鱼再次发现,既然我在洗涤阶段可以去干其他事,当我听到洗衣机洗涤完毕发出的滴滴声时我再回来进行甩干
那我为什么不能在甩干阶段也去干其他事情呢,当衣服甩干之后,洗衣机发出嘟嘟声,我听到嘟嘟声就知道甩干完毕了
于是在洗涤阶段和甩干阶段,咸鱼都不需要坐在小板凳上干等着,而是去干别的事情,当洗涤完毕或者甩干完毕的时候,洗衣机会发出滴滴或嘟嘟的声音
咸鱼听到声音就知道洗衣机洗涤或甩干完毕了,这时候他再过来处理衣服就行了
总结:
与信号驱动 I/O 类似,异步 I/O 模型在第一阶段通过信号回调的方式实现了进程的非阻塞
而在第二阶段,进程将数据从内核缓冲区 copy 到程序缓冲区的时候并非阻塞,而是同样设置一个信号回调,当 copy 完成后,进程收到通知,再去执行相应的操作
异步 IO 不仅仅是在第一阶段实现了信号回调,其也在第二阶段实现了信号回调,从而完全实现了异步 IO 操作