IO模型
按照《Unix网络编程》的划分,IO模型可以分为:阻塞IO、非阻塞IO、IO复用、信号驱动IO和异步IO,按照POSIX标准来划分只分为两类:同步IO和异步IO。
首先一个IO操作(read/write系统调用)其实分成了两个步骤:1)发起IO请求和2)实际的IO读写(内核态与用户态的数据拷贝)阻塞IO和非阻塞IO的区别在于第一步,发起IO请求的进程是否会被阻塞,如果阻塞直到IO操作完成才返回那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。同步IO和异步IO的区别就在于第二步,实际的IO读写(内核态与用户态的数据拷贝)是否需要进程参与,如果需要进程参与则是同步IO,如果不需要进程参与就是异步IO。如果实际的IO读写需要请求进程参与,那么就是同步IO。因此阻塞IO、非阻塞IO、IO复用、信号驱动IO都是同步IO,在编程上,这种非阻塞IO一般都采用IO状态事件+回调方法的方式来处理IO操作。如果是同步IO,则状态事件为读写就绪。此时的数据仍在内核态中,但是已经准备就绪,可以进行IO读写操作。如果是异步IO,则状态事件为读写完成。此时的数据已经存在于应用进程的地址空间(用户态)中。
在IO类型划分中,最重要的就是阻塞/非阻塞、同步/异步这两组概念。阻塞模式的IO会造成应用程序等待,直到IO完成。同时操作系统也支持将IO操作设置为非阻塞模式,这时应用程序的调用将可能在没有拿到真正数据时就立即返回了,为此应用程序需要多次调用才能确认IO操作完全完成。而同步与异步,更多地是在应用层面的概念,如果做阻塞IO调用,应用程序等待调用的完成的过程就是一种同步状况。相反,IO为非阻塞模式时,应用程序则是异步的。不过值得一提的是,在Linux的IO模型中,非阻塞与异步是不同的IO模型,这里的异步强调的是异步通知触发。
从应用的调度看,IO还可以根据以下维度进行划分:
-
大/小块IO:这个数值指的是控制器指令中给出的连续读出扇区数目的多少。如果数目较多,如64,128等,我们可以认为是大块IO;反之,如果很小,比如4,8,我们就会认为是小块IO,实际上,在大块和小块IO之间,没有明确的界限。
-
连续/随机IO:连续IO指的是本次IO给出的初始扇区地址和上一次IO的结束扇区地址是完全连续或者相隔不多的。反之,如果相差很大,则算作一次随机IO。连续IO比随机IO效率高的原因是:在做连续IO的时候,磁头几乎不用换道,或者换道的时间很短;而对于随机IO,如果这个IO很多的话,会导致磁头不停地换道,造成效率的极大降低。
-
顺序/并发IO:从概念上讲,并发IO就是指向一块磁盘发出一条IO指令后,不必等待它回应,接着向另外一块磁盘发IO指令。对于具有条带性的RAID(LUN),对其进行的IO操作是并发的,例如:raid 0+1(1+0),raid5等。反之则为顺序IO。