Linux的五种IO模型
阻塞IO:应用进程从发起IO系统调用,至内核空间中的数据就绪,这个期间处于阻塞状态。
非阻塞IO:应用进程发起IO系统调用后立刻返回。应用进程可以不断(轮询)发起IO系统调用,直至数据就绪,再将数据从内核空间拷贝到用户空间进行数据处理。(在拷贝数据的过程,进程仍然属于阻塞状态)。优点是进程发起I/O操作时,不会因为数据还没就绪而阻塞。缺点是增大了响应延迟,因为每过一段时间才会发起系统调用检查数据是否就绪,而任务可能在两次轮询之间的时间完成,这会导致整体数据吞吐量的降低;尤其是在本地I/O,内核读取数据很快,这种模式下多了至少一次系统调用,而系统调用是比较消耗CPU的操作。
IO多路复用:应用进程借助select或poll或epoll,通过发起这种系统调用,可以让内核监听注册的多个事件(传入file descriptor和感兴趣的事件readable、writable等),当其中有就绪的数据后,就会返回结果,再由应用进程发起真正的IO系统调用(read、recvfrom等),来完成数据读取。优点是优化了非阻塞IO大量发起系统调用的问题,且一次可以监控大量的fd,但仍然存在阻塞)。
- select(): 等待内核返回后,需要轮询所有fd找出就绪的fd,随着fd数量增加,性能逐渐下降
- poll(): 和select()差不多,只有linux支持poll。
- epoll(): 不需要轮询,直接返回就绪的fd,用以替代select()和poll()
信号驱动IO:应用进程向内核注册一个信号处理程序,发起系统调用后立即返回,不会阻塞。当内核中数据就绪后,会发送信号给应用进程,应用进程在信号处理程序中发起真正的 IO 系统调用完成数据读取。
异步IO:应用进程程发起aio_read系统调用,无论内核数据是否就绪,都会直接返回给用户进程,然后用户进程不会阻塞,而是可以去做别的事情。等数据就绪后,内核直接复制数据到用户空间给到进程,然后内核向进程发送在aio_read中指定的信号。异步IO在IO的两个阶段,进程都是非阻塞的。它就像用户进程将整个IO操作交给了内核来完成,然后内核完成后发信号通知。在此期间,用户进程不需要去检查IO操作的状态,也不需要主动地去拷贝数据。
POSIX对同步IO和异步IO定义是:同步I/O操作将会造成请求进程阻塞,直到I/O操作完成;异步I/O操作不会造成进程阻塞。 因此根据此定义,前面4种I/O模型都是同步I/O,因为它们在第二阶段的I/O操作(recvfrom
)都会造成进程阻塞。只有最后一个I/O模型匹配异步I/O的定义。
NIO三大组件
Reference
带你彻底理解Linux五种I/O模型
python的twisted