• select,poll,epoll,IO多路复用进化史


      IO多路复用中的 “多路” 指的是同时监听多个打开文件(socket或者其他文件设备),“复用” 指的是复用一个 进程/线程 去监听这些打开文件

    1.最早期的select

      伪代码表示:

        while (true) {
            for (fd : 监听的fd) {
              if (poll(设备)){
              返回就绪数 + 1;
      
    break;   } }
         
    if (返回就绪数 > 0) {
             free_wait();
    break; } else {     sleep();   } }

    free_wait 是从所有设备的等待队列中移除当前进程,在等待队列中的每个节点是 wait_queue_t 结构体的内存实例

    当 设备就绪的时候,对设备的 poll 函数调用 会返回 true

    假如要监听的文件数是 N,那么每次都要去都要去轮询所有的 设备,而不是轮询到一个就绪就停下来,因为要去计数有多少个就绪了

    在就绪数量 > 0 的时候,又要调用 free_wait 去遍历所有要监听文件的 等待队列,如此一来,并且下一次调用 select 的时候,也要重复上述流程。

    导致 select 每次调用的 时间复杂度是 O(N)

    2. poll

      poll 和 select 一样,也是去轮询,时间复杂度也是 O (N) , 但是 poll 的监听对象不是用数组存储的,而是以链表存储的,一般select只支持监听 1024 个打开文件

      但是 poll 只要内存充足,就能监听远不止 1024 个打开文件

    3. epoll

      select 和 poll 之所以低效,是因为每次的轮询,轮询到的大部分打开文件,可能都是未就绪状态

    epoll 做的优化思路清晰,只把就绪的打开文件返回给 用户空间。具体的做法是 通过 epoll_create 创建 epollevent ,epollevent 内维护两个重要的数据结构:

      1.一颗便于查找的红黑树,红黑树的节点是待监听的打开文件号 + 待监听事件(其他内容省略)(rbr)

      2.一条便于增删改的双向链表,节点和上面一样,是打开文件号 + 待监听事件(其他内容省略),代表就绪的打开文件号 (rdlist)

          

      通过 epoll_ctl 添加 打开文件号 + 待监听事件 的时候,会把打开文件号 + 待监听事件打包成一个节点(epoll_item), 并且加入到上述的红黑树 和 双向链表中

      同时 创建一个 epoll_entry ,这种数据结构中有成员 wait_queue_t , wait_queue_t 就是设备的等待队列上节点的类型

       

      把epoll_entry 的 wait_queue_t 做为一个节点链入到 设备的等待队列中去,并且设置回调函数

      等待设备就绪的时候,驱动程序会清空等待队列,清空的方法是把等待队列的节点移除并且调用节点的回调函数

      这里的回调函数是直接唤醒 epollevent 的 wq 上等待的进程,调用 epoll_wait 的进程会被加入到 wq 上 

        

      最后,就是调用 epoll_wait 等待打开文件就绪

      值得提问的是,是不是每次一个设备就绪,就唤醒进程,那不是经常因为一个设备就被唤醒?确实可能,但是在唤醒期间,如果有多个其他设备就绪,他们也会把自己的打开文件号放到 rdlist 上

      那不会出现并发冲突吗?比如进程刚好被唤醒去拿 就绪队列上的节点,复制到自己传入的参数events数组(存储就绪的文件打开号和事件)上,并且清空就绪队列,这时候其他就绪设备把自己挂到就绪队列了怎么办?

      复制 - 清空 的过程有 eventpoll 的 mutex 互斥量 保证并发安全,不用担心。

      如果正好 复制 - 清空的时候,有新的就绪设备要将自己挂到就绪队列的话,没挂上就被阻塞。等待复制-清空完成再把自己挂上去。

      下一次 epoll_wait 的时候,因为就绪队列上有节点,所以直接 复制-清空 后返回,不阻塞

      

     

  • 相关阅读:
    Android学习笔记_10_ContentProvider内容提供者的使用
    Android学习笔记_9_SQLiteOpenHelper对象之数据库增删改查以及事务回滚操作
    Android学习笔记_8_使用SharedPreferences存储数据
    Android学习笔记_7_使用 sax 或者 dom 或者 pull 解析XML文件
    Android学习笔记_6_保存文件到SDCard
    java GZIP 压缩数据
    struts2 实现文件下载方法汇总
    javascript ActiveXObject FileSystemObject 对象,创建、复制、删除、读取文件等
    css块元素的 display 属性 inline-block 的应用
    javascript操作Date对象
  • 原文地址:https://www.cnblogs.com/lqlqlq/p/13995486.html
Copyright © 2020-2023  润新知