Unix下有5种IO模型:
-
阻塞IO
针对阻塞IO的系统调用(如read, write)可能因为无法完成而被系统挂起,直到等待的事件发生为止。通俗的解释,用户进程(也有叫应用进程的)需要进行IO操作,如调用read,如果内核中的数据没有准备好,用户进程就阻塞,直到内核数据拷贝到了用户缓冲区,用户进程才返回。采用这种方式在需要进行IO的进程很多的时候,由于大部分的进程都是处于阻塞状态,会带来很大的进程切换开销,和内存开销。
-
非阻塞IO
针对非阻塞IO的系统调用总是立刻返回,不管事件是否发生,如果事件没有立刻发生就返回-1,并且设置errno,就类似于出错了。通俗的解释,用户进程(也有叫应用进程的)需要进行IO操作,如调用read,如果内核中的数据没有准备好,用户进程立刻返回,并设置errno,用户进程需要不断地向内核查询事件是否完成,因此采用这种方式会占用大量的CPU资源。
-
IO复用
IO多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。
-
信号驱动(signal-driven)
就是内核在文件描述符就绪的时候以信号SIGIO的方式通知应用进程。
前面四种都是属于同步IO模型。POSIX对于同步IO操作以及异步IO操作的定义是:
同步IO操作:导致请求进程阻塞,直到IO操作完成(也就是内核将数据写到用户空间)。
异步IO操作:不导致请求进程阻塞。
-
异步IO(asynchronous)
Linux中,可以调用 aio_read 函数告诉内核描述字缓冲区指针和缓冲区的大小、文件偏移及通知的方式,然后立即返回,当内核将数据拷贝到缓冲区后,再通知应用程序,这里使用了特殊的API。
5种IO模型的区别:
图中对于IO复用的产生的系统调用事实上是可以设置为不阻塞的,这是这幅图不太严谨的地方。
PS:
想要真正理解五种IO模型,我建议还是好好看看UNP 卷1相关的内容,光看博客是理解不深刻的。
参考资料:
- Linux高性能服务器 游双
- UNP 卷1
- https://www.nowcoder.com/courses/cover/live/504