Unix系统IO模型简介
阻塞式IO
阻塞式IO,即调用IO函数之后阻塞,知道IO操作完成后返回,继续进行接下来的操作。
非阻塞式IO
进程把一个套接字设置成非阻塞是在通知内核:当所请求的IO操作不能立即完成而需要睡眠等待时,不要把本进程进入睡眠,而是返回一个错误。
IO多路复用
IO多路复用的方法有select、poll、epoll三种。调用select、poll、epoll这三者中的一个,进程会阻塞在这里,而不是阻塞在真正的IO操作上。IO多路复用的优势在于可以等待多个描述符就绪。
与IO多路复用密切相关的另一种IO模型是在多线程中使用阻塞式IO,这种模型与上述模型极为相似,但它没有使用select阻塞在多个文件描述符上,而是使用多个线程(每个文件描述符一个线程),这样每个线程都可以自由地调用阻塞式IO函数了。
信号驱动IO
开启套接字的信号驱动IO功能,并通过sigaction系统调用安装一个信号处理函数。该系统调用将立即返回,我们的进程继续工作,也就是说它没有被阻塞。当数据报准备好读取时,内核就为该线程产生一个SIGIO信号。我们随后可以在信号处理函数中调用IO函数,并通知主循环数据已经准备好待处理,也可以直接通知主循环,让它执行IO操作。
异步IO
异步IO函数的工作机制是:告知内核某个IO操作,并让内核在整个操作(包括数据在用户和内核缓冲区之间的复制)完成后再通知我们。这种模型与信号驱动模型的主要区别在于:信号驱动式IO是由内核通知我们何时可以启动一个IO操作,而异步IO模型是由内核通知我们IO操作何时完成。
在上图中,我们调用aio_read函数,给内核传递描述符、缓冲区指针、缓冲区大小和文件偏移,并告诉内核当整个操作完成时如何通知我们。该系统调用立即返回,而且在等待IO完成期间,我们的进程不被阻塞。
值得一提的是Linux下主要有两套异步IO,一套是由glibc基于线程和阻塞IO实现的,据说性能很差。另一套是有Linux内核实现,并由libaio来封装调用接口。