UNIX下IO模型分析

UNIX下IO模型分析

UNIX下的五种常见IO模型分析,帮助理解

IO操作的两个阶段

以读数据操作为例:
1. 等待内核数据准备(数据拷贝到内核缓冲区)
2. 将数据从内核拷贝到用户空间

IO模型

UNIX下共有五种常见的IO模型:
UNIX下共有五种常见的IO模型

下面以recvfrom接口举例

阻塞IO

默认情况下,所有的套接字都是阻塞的
阻塞IO
调用recvfrom接口,进程在IO操作的两个阶段都会阻塞,直到最终数据拷贝到用户空间或者过程中出现错误才会返回,进程在阻塞状态下是不占用CPU资源的

最常见的错误是发生系统中断,此时需要重读,可参考这里

非阻塞IO

可以通过fcntl(sockfd,F_SETFL,O_NONBLOCK)将套接字设置成非阻塞
非阻塞IO
调用recvfrom接口,无论内核缓冲区是否有可用数据,进程都会立即返回,所以在IO操作的第一阶段是非阻塞的; 若无数据可用,内核将errno设置为为EWOULDBLOCK或者EAGAIN,进程可以使用轮询的方法,保证内核在数据准备好时,能立即拷贝到用户空间; 若有则立即将数据拷贝到用户空间,进程在数据拷贝到用户空间即IO操作的第二阶段是阻塞的;

非阻塞IO过于消耗CPU时间,将大部分时间用于轮询

多路复用IO

多路复用系统调用:select,pollepoll,其中windows平台不支持pollepoll,使用方法可以参考I/O 多路复用之select、poll、epoll详解Linux select/poll和epoll实现机制对比
 多路复用IO
调用select,等待内核数据准备,所以IO操作的第一个阶段,进程是阻塞的,不过是阻塞在多路复用系统调用上,而不是IO系统调用上; 当select返回套接字可读条件时,再调用recvfrom将数据从内核拷贝到用户空间,IO操作的第二阶段,进程是阻塞的

多路复用IO和阻塞IO,在IO操作的两个阶段都是阻塞的,不过多路复用IO使用了两个系统调用,而阻塞IO只使用了一个,所以在连接数不是很多的情况下,阻塞IO可能性能更佳; 多路复用IO的优势在于可以同时监控多个用于IO的文件描述符。

多线程中的阻塞IO,与多路复用IO极为相似

信号驱动IO

信号驱动IO
调用sigaction等系统调用安装信号处理函数,并立即返回,所以IO操作的第一阶段,进程是非阻塞的; 当内核数据准备好时,内核会产生一个信号,通知进程将数据从内核拷贝到用户空间,IO操作的第二阶段,进程是阻塞的

使用方法:IO的多路复用和信号驱动

异步IO

异步IO有一组以aio开头的系统调用,使用方法可参考Linux AIO机制
异步IO
调用异步IO系统调用,给内核传递描述字、缓冲区指针、缓冲区大小(与read相同的三个参数)、文件偏移(与lseek类似),告诉内核当整个操作完成时如何通知我们,并立即返回,在IO操作的两个阶段,进程都不阻塞

总结

5种IO模式比较
- 同步IO和异步IO的主要区别是将数据从内核拷贝到用户空间是否阻塞,前者会在将数据从内核拷贝到用户空间时即IO操作的第二个阶段发生阻塞,而后者则在系统调用后直接返回,直到内核发送信号通知IO操作完成,在IO操作的两个阶段都没有阻塞
- 阻塞IO和非阻塞IO的主要区别是系统调用是否立即返回(默认将数据从内核拷贝到用户空间即IO操作的第二个阶段是立即返回的),前者会在IO操作的两个阶段完成前一直阻塞,后者在内核没有准备好数据的情况下立即返回,即只会在IO操作的第二个阶段阻塞
- 信号驱动IO和异步IO的主要区别在于前者由内核通知我们何时启动一个IO操作,在将数据从内核拷贝到用户空间过程中即IO操作的第一个阶段依旧是阻塞的,而后者是由内核通知我们IO操作何时完成,在IO操作的两个阶段都没有阻塞

知乎上有一个比较生动的例子可以说明这几种模型之间的关系。

Reference

About me

forthebadge
- GitHub:AnSwErYWJ
- Blog:http://www.answerywj.com
- Email:[email protected]
- Weibo:@AnSwEr不是答案
- CSDN:AnSwEr不是答案的专栏

Creative Commons License This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。

猜你喜欢

转载自blog.csdn.net/u011192270/article/details/73826651