一个输入操作通常有两个阶段:
- 等待数据准备,即从存储介质(磁盘,网络等)拷贝到内核;
- 从内核向进程复制数据
阻塞I/O
- 应用进程被阻塞,直到数据从内核缓冲区复制到应用进程缓冲区中才返回
非阻塞I/O
- 应用进程执行系统调用之后,内核返回一个错误码。应用进程可以继续执行,但是需要不断的执行系统调用来获知 I/O 是否完成,这种方式称为轮询(polling)。
I/O复用
- 使用 select 或者 poll 等待数据,并且可以等待多个套接字中的任何一个变为可读。这一过程会被阻塞,当某一个套接字可读时返回,之后再使用 recvfrom 把数据从内核复制到进程中;
- 它可以让单个进程具有处理多个 I/O 事件的能力。又被称为 Event Driven I/O,即事件驱动 I/O。
信号驱动I/O
- 通过系统调用 sigaction 安装一个信号处理程序。此系统调用立即返回,进程继续工作,它是非阻塞的;
- 当数据报准备好被读时,就为该进程生成一个SIGIO信号;
- 应用进程收到之后在信号处理程序中调用 recvfrom 将数据从内核复制到应用进程中。
异步I/O
- 应用进程执行 aio_read 系统调用会立即返回,应用进程可以继续执行,不会被阻塞,内核会在所有操作完成之后向应用进程发送信号;
- 调用aio_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 在第一阶段不会阻塞。