一次IO的两个阶段:
- Waiting for the data to be ready(等待数据到达内核缓冲区);
- Copying the data from the kernel to the process(从内核缓冲区拷贝数据到程序缓冲区))
IO模式
模式 |
特点 |
阻塞 I/O(blocking IO) |
在IO执行的两个阶段都处于blocked(阻塞)状态 |
非阻塞 I/O(nonblocking IO) |
用户进程需要不断的主动询问kernel数据,相当于copy data from kernel to user)依然处于一个阻塞状态 |
I/O 多路复用( IO multiplexing) |
两个阶段的都是阻塞状态,但是可以同时监听多个文件描述符。 |
信号驱动 I/O( signal driven IO) |
在实机生产环境中并不常用 |
异步 I/O(asynchronous IO) |
相比信号驱动IO,异步IO两个阶段都是非阻塞的 |
- 阻塞式IO(默认),非阻塞式IO(nonblock),IO复用(select/poll/epoll),signal driven IO(信号驱动IO)都是属于同步型IO。
IO多路复用的机制
机制 |
特点 |
select |
良好跨平台支持,单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024 |
poll |
pollfd并没有最大数量限制(但是数量过大后性能也是会下降)。 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。 |
epoll |
Linux系统专有,在2.6内核中新增。更加灵活,没有描述符限制。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。 |
- select和poll都需要在返回后,通过遍历文件描述符来获取已经就绪的socket。事实上,同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。
- select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。
epoll的两种模式
- 边缘触发(ET:edge-triggered):是高速工作模式,只支持no-block socket,当状态有变化或发生了某种事件就发出通知;
- 水平触发(LT:level triggered):是默认的工作方式,同时支持block和no-block socket,当处于某种状态或具备某种条件就发出通知;
- ET和LT的区别:LT事件不会丢弃,只要读buffer里面有数据可以让用户读,则会不断通知你。而ET则只在事件发生之时通知。
epoll优点
- 当检查大量的文件描述符时,epoll的性能延展性比select和poll高很多;
- epoll API既支持水平触发也支持边缘触发,select和poll只支持水平触发,信号驱动只支持边缘触发;
- 性能方面,epoll可以避免复杂的信号处理流程;
- 灵活性高,可以指定我们希望检查的事件类型。
参考
Linux五种IO模型浅谈
Linux IO模式及 select、poll、epoll详解