zoukankan      html  css  js  c++  java
  • epoll相比select,poll的2个改进点

    改进点

    1. epoll把select,poll的功能进行了拆分: 1个api拆分为3个api
    2. 维护就绪列表,不用每次遍历全部fd寻找就绪fd进行处理,而是直接拿到就绪fd进行处理。=> 空间换时间,我把就绪fd存放到某个地方,就不需要遍历了。

    // 附录2

    int s = socket(AF_INET, SOCK_STREAM, 0);  
    bind(s, ...)
    listen(s, ...)
    int fds[] =  存放需要监听的socket
    while(1){
        int n = select(..., fds, ...) // ydd:可以看到这里,每次都需要把全部fds集合传递进去。=> 能不能只传1次
        for(int i=0; i < fds.count; i++){ // ydd: 每次都需要遍历全部fd,然后查找可读的fd进行操作。=> 能不能只返回有事件触发的fd
            if(FD_ISSET(fds[i], ...)){
                //fds[i]的数据处理
            }
        }
    }
    
    1. select低效的原因之一是将“维护等待队列”和“阻塞进程”两个步骤合二为一。 // 因为select只有1个api, 整个都放在while循环中,存在冗余和浪费。
      epoll将这两个操作分开,先用epoll_ctl维护等待队列,再调用epoll_wait阻塞进程。// epoll有3个api,把事情分开做了,只有最后一个api放在while循环中。

    2. select低效的另一个原因在于程序不知道哪些socket收到数据,只能一个个遍历。如果内核维护一个“就绪列表”,引用收到数据的socket,就能避免遍历。如下图所示,计算机共有三个socket,收到数据的sock2和sock3被rdlist(就绪列表)所引用。当进程被唤醒后,只要获取rdlist的内容,就能够知道哪些socket收到数据。

    int s = socket(AF_INET, SOCK_STREAM, 0);   
    bind(s, ...)
    listen(s, ...)
    
    int epfd = epoll_create(...);
    epoll_ctl(epfd, ...); //将所有需要监听的socket添加到epfd中
    
    while(1){
        int n = epoll_wait(...)
        for(接收到数据的socket){
            //处理
        }
    }
    

    epoll引入了只触发一次的事件通知方式

    条件触发

    // 附录1
    满足条件一直触发,这也是select,poll的触发方式。

    • 附录1的前几个评论
    https://github.com/linuxxiaoyu/block
    执行后都会重复打印”need read socket_fd“和“poll need to read”,所以select和poll应该都是条件触发
    

    边缘触发

    只触发一次,所以效率很高,特有的触发方式。
    Q: 如果只触发一次,那数据没有读取完,怎么办?

    参考

    1. 23 | Linux利器:epoll的前世今生
    2. 如果这篇文章说不清epoll的本质,那就过来掐死我吧! (1)
  • 相关阅读:
    MFC总结
    工作项目总结
    关于多线程使用sqlite3的问题
    vs调试时,不显示局部变量
    oracle和mysql互相迁移
    oracle如何设置ip访问数据库
    win7 安装oracle 11g图文步骤
    Mybatis传参
    别纠结mybatis啦,赶紧来瞅瞅吧
    程序员和管理常用的网站地址
  • 原文地址:https://www.cnblogs.com/yudidi/p/12662392.html
Copyright © 2011-2022 走看看