[toc]
I/O模型
阻塞I/O
blocking-io-mode最常见的I/O模型,默认情况下通过read或者write等系统调用读写文件或者网络时,都会被阻塞
操作系统中多数的I/O操作如上,一旦执行,会陷入阻塞等待I/O操作ready。
非阻塞I/O
可以通过 O_NONBLOCK
字段标志为非阻塞的。
int flags = fcntl(fs,F_GETFL,0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
通过fcntl
和O_NONBLOCK
我们可以把一个文件描述符修改为非阻塞的。此后当我们进行read操作的时候,如果数据没有ready,则会返回EAGAIN
的错误。如果已经ready,则它的返回值大于0。
异步I/O
image-20210206160159479同步方式在处理I/O事件的时候,必须阻塞在某个方法上面等待I/O事件完成。(无论阻塞I/O,还是上面说的非阻塞式I/O都是同步的)。上面的非阻塞只是我们不需要阻塞等待数据ready,但是真正的io操作还是阻塞的。
异步的方式,就是将所有的I/O读写交给操作系统去处理。
异步IO跟信号驱动IO很相似,但是不同点如上所说,触发的时机不一致。异步io只是在所有操作都ready的时候才会通知。
对于一次I/O访问,可以分为2部分:
- 等待数据准备就绪
- 将数据从内核copy到进程。
I/O复用
目前最多的实现,单独放到一章去讲,这里给出大概交互
image-20210206160600266信号驱动I/O
监听io信号,等数据ready之后开始处理
image-20210206161145085无论如何处理SIGIO信号,这种模型的优势在于等待数据报到达期间进程不 被阻塞。主循环可以继续执行,只要等待来自信号处理函数的通知:既可以是数 据已准备好被处理,也可以是数据报已准备好被读取。
五种I/O模型对比
image-20210206161256697前4种模型的主要区别在于第 一阶段,因为它们的第二阶段是一样的:在数据从内核复制到调用者的缓冲区期 间,进程阻塞于recvfrom调用。相反,异步I/O模型在这两个阶段都要处理,从 而不同于其他4种模型。
前4种模型——阻塞式I/O模型、非阻塞式I/O模型、I/O 复用模型和信号驱动式I/O模型都是同步I/O模型,因为其中真正的I/O操作 (recvfrom)将阻塞进程。只有异步I/O模型与POSIX定义的异步I/O相匹配。
I/O多路复用
鉴于目前这是最常用的方式,所以单独说说
开始之前的个人疑问
-
IO多路复用跟信号驱动有什么不同。
信号驱动的使用比较少,应该是不灵活
一种在单个线程上同时处理多个事件流的方法
select
image-20210206173828848缺点:
- 文件描述符数量限制
- 线性扫描,性能很差
- fd维护
poll
缺点:
- 大量的fd数组被整体复制于内核态和用户态之间,而不管这样的复制是不是有意义。
- 同select相同的是调用结束后需要轮询来获取就绪描述符。
epoll
轮询改为定点
网友评论