Linux : I/O 模型
文章目录
- 1. 五种I/O模型
- 2. I/O本质
- 3. 同步/异步通信
1. 五种I/O模型
Linux中,有五种常见的I/O模型:阻塞I/O,非阻塞I/O,IO多路转接,信号驱动IO,异步IO。
阻塞I/O:
阻塞I/O就是一直等待系统内核中相关读写条件就绪时,再正常读写,并返回。阻塞IO是网络套接字通信中,最常见的I/O方式。
非阻塞I/O:
与阻塞I/O相反,不等待系统内核中相关读写条件就绪,即如果读写条件不满足,也直接返回。由于非阻塞I/O的处理逻辑,在该模式下,如果想要正常读写数据,需要在用户层额外维护轮询逻辑。
信号驱动I/O:
信号驱动I/O本质是不直接进行I/O读写,而是借由信号驱动,即进行一系列设置,使得系统内核在相关文件描述符fd的读写条件就绪时发送SIGIO信号,用户层通过设置信号处理函数,进入信号处理逻辑,然后在信号处理逻辑中,使用write/read进行读写。
I/O多路转接:
I/O多路转接本质上类似于阻塞I/O,但是它与阻塞I/O的不同点在于:阻塞I/O的等待是等一个文件描述符的相关读写条件就绪,而多路转接是等多个文件描述符的相关读写条件就绪,而只要其中一个文件描述符相关读写条件就绪,多路转接I/O就可以返回,不用再等。
异步I/O:
解释异步I/O之前,先要明白什么是同步I/O。
上述所介绍的四种I/O模型,本质都是同步I/O。简单来说,只要在用户层实际参与了相关I/O逻辑,那么就是同步I/O。
相反地,如果在用户层没有参与任何实际I/O逻辑,而是直接将相关I/O逻辑全权交给内核处理,那么这就是异步I/O。
Linux中的异步I/O,本质就是通过aio_read系统调用,将相关fd的I/O处理全部交给系统内核完成。而系统内核完成相关I/O处理后(等待读写条件就绪+实际读写行为),通过信号通知用户,进入用户的相关信号处理逻辑,如果以读数据为例,此时用户不需要再调用read,因为内核已经read过了,只需要拿到相应缓冲区,直接在用户层进行数据处理即可——这也是异步I/O和信号驱动I/O的最大区别。
2. I/O本质
I/O的本质是什么?
通过上述五种模型的介绍,我们可以清晰认识到I/O的本质就是:等+拷贝。
等就是等待读写条件就绪的过程,拷贝就是实际读写的过程,实际的读写不就是将数据从用户层拷贝到内核中,或者从内核中拷贝用户层吗?
因此,我们如果分析I/O的效率,不考虑其它消耗,仅就I/O本身而言进行考虑,就是考虑 等 + 拷贝 这个过程的效率。
实际上,大部分I/O的时间消耗都在等上面,拷贝的时间消耗占比是较小的,而且拷贝的过程是必须进行的,难以优化。
所以,在这种情况下,优化I/O时间,本质就是如何优化等的时间。而实际上,等的时间本质也是固定的,数据要5s之后才会到来,那么就得等到5s之后,因此关键在于如何复用“等”的时间。如果能够复用“等”的时间,本质上还是等了相应时间才能处理相关数据,但是复用“等”的时间,程序完成了其它任务,进而提高了整个程序的效率,于是可以理解成变相提高了I/O效率。
上述I/O模型中,非阻塞I/O,信号驱动I/O,多路转接I/O,异步I/O,本质都是通过复用“等”的时间,进而变相提高I/O效率的。
3. 同步/异步通信
同步与异步这一对概念在计算机世界中可谓应用非常广泛,很多领域中都会涉及同步与异步——需要注意的是,在不同的领域中,同步/异步的概念可能会有所差异。
那么,在通信中,同步和异步分别表示什么呢?
简单来说,同步通信就是用户主动关心通信状态,无论是阻塞式关心,还是非阻塞式轮询关心,同步通信要求用户层主动维护关心通信状态的逻辑。
异步通信则刚好相反。用户并不主动关心通信状态,自身干着与关心通信状态无关的事,直到被别人通知了相关通信状态已经就绪,才会进入通信的相关处理逻辑,否则完全不关心通信状态,而在其它处理逻辑中。
如果利用同步/异步通信的概念对上述五种I/O模型进行划分的话,那么阻塞I/O,非阻塞I/O,多路转接I/O属于同步通信,而信号驱动I/O和异步I/O则属于异步通信。从这里我们也可看出,IO的同步/异步与通信的同步/异步是有所不同的。
