select poll epoll 总结

IO多路复用

IO多路复用是个由来已久的东西,看过很多资料,甚至于看过很多遍资料但是没有自己总结或者再梳理一遍终究理解会没那么强。英文全称为 IO Multiplexing。 Multiplexing 就是多路 multi。整个意思理解为IO的多路复用。

为什么会有IO多路复用

IO多路复用使用了一个线程(一个独立执行链)对多个IO进行监控。在没用这个概念之前都是一对一的关系,也就是客户端进来一个请求,我就相应的开一个线程去做处理。而第一个IO复用的做法就是select。

select

select 是最早设计出来支持IO多路复用的技术。其工作流程如下:
这里写图片描述

  1. 从用户态通过 copy_from_user 拷贝fd_set到内核态
  2. 注册回调函数__pollwait
  3. 遍历所有fd,调用其对应的poll方法(用户态传过来的值)
  4. __pollwait的主要工作就是把current(当前进程)挂到设备的等待队列中,不同的设备有不同的等待队列,对于tcp_poll来说,其等待队列是sk->sk_sleep(注意把进程挂到等待队列中并不代表进程已经睡眠了)。在设备收到一条消息(网络设备)或填写完文件数据(磁盘设备)后,会唤醒设备等待队列上睡眠的进程,这时current便被唤醒了。
  5. poll方法返回时会返回一个描述读写操作是否就绪的mask掩码,根据这个mask掩码给fd_set赋值。
  6. 设备上有资源可读写,唤醒休眠进程,或者是schedlue_timeout 也唤醒进程。
  7. 把相应的fd_set再次拷贝到用户态。

select缺点

  • 每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
  • 同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
  • select支持的文件描述符数量太小了,默认是1024

关于第三点是可以修改的 通过ulimit -n 查看。这个限制在内核代码中被写死,可以通过启动过程中加载脚本的方式再次修改为想要的参数。 相关链接文件描述符限制修改

poll 实现

poll的实现和select非常相似,只是描述fd集合的方式不同,poll使用pollfd结构而不是select的fd_set结构,其他的都差不多。

poll改进点

  • poll 去掉了1024个链接的限制。

epoll 实现

通过以上select的缺陷我们可以知道。其有3个缺点。poll只是改进了一点,不做数量限制,但是这个对性能的提升并没有什么卵用。关键在于后面的前面两点。所以epoll针对这两点进行了改善。

  • 如果改善fd拷贝?
    在select的方案中每次select都会把fd重新拷贝一份,这其中也是因为select相当于两个功能,既做了fd数组的传入也做了对应wait操作。而fd的改动毕竟的少量的,所以这里把一个系统调用拆开成了两个系统调用。于是,epoll引入了epoll_ctl系统调用,将高频调用的epoll_wait和低频的epoll_ctl隔离开。
  • epoll_ctl通过(EPOLL_CTL_ADD、EPOLL_CTL_MOD、EPOLL_CTL_DEL)三个操作来分散对需要监控的fds集合的修改,做到了有变化才变更,将select或poll高频、大块内存拷贝(集中处理)变成epoll_ctl的低频、小块内存的拷贝(分散处理),避免了大量的内存拷贝。

如何减少遍历fd?
在实现上把简单粗暴的遍历改为了对reay_list的遍历。这里就需要引入中间层,ready_list以及wait_queue. 相关的原理还不是特别清楚。待后续学习。
epoll的解决方案不像select或poll一样每次都把current轮流加入fd对应的设备等待队列中,而只在epoll_ctl时把current挂一遍(这一遍必不可少)并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表)。epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd(利用schedule_timeout()实现睡一会,判断一会的效果.

水平触发 边缘触发

水平触发简单的理解就是 处在某种状态的时候都会触发。
边缘触发 只有在状态改变的时候才会触发。

对应的水平触发 会把相关的事件再次放入到ready_list中。

相关链接:腾讯云
https://www.cnblogs.com/Anker/p/3265058.html

猜你喜欢

转载自blog.csdn.net/u012279631/article/details/80703504