Linux五种I/O模型
I/O阶段
典型的一次I/O分为两个阶段:数据就绪和数据读写
- 数据就绪:根据系统I/O操作的就绪状态
- 阻塞
- 非阻塞
区别在于:进程发起系统调用后,是会被挂起直到收到数据后再返回,还是立即返回成功或错误。
- 数据读写:根据应用程序和内核的交互方式
- 同步
- 异步
区别在于:将数据从内核复制到用户空间时,用户进程是否会阻塞(需要用户进程来完成)
Linux五种I/O模型
阻塞I/O (blocking)
调用者调用了某个函数,等待这个函数返回,期间什么也不做,不停的去检查这个函数有无返回,必须有返回后才能进行下一步动作
非阻塞I/O (NIO)
非阻塞等待,每隔一段时间就去检测IO事件是否就绪。没有就绪就可以做其它事。非阻塞I/O执行系统调用总是立即返回,不管事件是否已经发生,若事件没有发生,则返回-1,此时可以根据errno区分这两种情况,对于accept,recv和send,事件未发生时,errno通常被设置成EAGAIN。
I/O复用 (IO multiplexing)
Linux用select/poll/epoll函数实现IO复用模型,这些函数也会使进程阻塞,但和阻塞IO所不同的是这些函数可以同时阻塞多个IO操作。而且可以同时对多个读操作,写操作的IO函数进行检测,直到有数据可读或可写时,才真正调用IO操作函数。
信号驱动I/O (signal-driven)
Linux用套接口进行信号驱动I/O,安装一个信号处理程序,进程继续运行并不阻塞,当I/O事件就绪,进程收到SIGIO信号,然后处理IO事件。
异步I/O (asynchronous)
Linux中,可以调用aio_read()
函数告诉内核该描述符缓冲区指针和缓冲区的大小,文件偏移及通知的方式,然后立即返回该函数调用状态(函数调用成功与否)。当内核将数据拷贝到缓冲区后,再通知应用程序。
五种I/O模型的对比
- 同步I/O模型要求用户代码自行执行I/O操作(将数据从内核缓冲区读入用户缓冲区,或将数据从用户缓冲区写入内核缓冲区);
- 异步I/O机制则由内核来执行I/O操作(数据在内核缓冲区和用户缓冲区之间的移动是由内核在”后台完成的”)。
- 同步I/O向应用程序通知的是I/O就绪事件
- 异步I/O向应用程序通知的是I/O完成事件