• 贺荣伟
    2019-10-26
    这篇文章写得非常棒!之前学 epoll,只会流于表面,也很少去深度剖析底层的数据结构,多读几遍!
    另外分享一个大佬同学 epoll 内核源码详解发的帖子:https://www.nowcoder.com/discuss/26226

    作者回复: 赞分享。

    
     1
  • 鱼向北游
    2019-10-18
    select这种是把等待队列和就绪队列混在一起,epoll根据这两种队列的特性用两种数据结构把这两个队列分开,果然在程序世界没有解决不了的事情,如果有,就加一个中间层

    作者回复: 你这个理解倒是比较有趣,程序是伟大的。

    
     1
  • HerofH
    2020-01-15
    首先感谢老师的精彩分析。

    然后说下我的个人理解:epoll之所以效率比select高,原因在于select要做的事情太多,每次调用select不仅需要将描述符集添加到监听队列中,还要负责监听事件发生后的处理,以及select最后的清理工作等等...
    而epoll则把这么多事情分到了epoll_ctl和epoll_wait去处理,调用epoll_ctl可以开启事件的监听工作,epoll_wait则可以完成对已激活的事件的处理工作,最后close(epfd)完成epoll的清理工作。
    而select和epoll_wait是循环中反复调用的,epoll_wait做的事情比select少多了,因此从这个角度来说epoll效率会比select效率高。
    除此之外,个人感觉epoll还有一个妙处就是就绪链表,当监听的事件发生后,相应的epitem会自动在监听回调中将其添加到就绪链表中,而对于select来说,则需要不停对所有监听的描述符进行遍历,来检查它们的状态。

    不知道理解是否正确,敬请指正。
    展开

    作者回复: 👍

    
    
  • Geek_68d3d2
    2020-01-08
    epi>nwait >= 0请问这行代码什么意思

    作者回复: 对应的文件描述字上有poll的动作,正在等待事件发生。

    
    
  • godtrue
    2019-12-01
    功力不够,读起来有些费劲,好似拿到了九阴真经,不过需要黄姑娘翻译一下!
    如果能来个图,就好了😁

    作者回复: 待我找黄姑娘来:)

    
    
  • haozhang
    2019-11-06
    老师 进程阻塞的形式是什么呢 是for死循环吗 还是加入到等待队列呢,我看for循环前面不是加入到等待队列了吗?

    作者回复: 进程阻塞其实就是把CPU时间调度给了其他的进程,因为得不到CPU时间,所以当前进程的代码没有办法再执行下去,表现的行为就是当前程序执行"休眠"在那里了。

    这里的等待队列是LInux内核把等待调度的进行按照自己内部的数据结构,形成了一个队列。按照LInux内核任务调度算法进行调度,来唤醒对应的"休眠"进程。

    
    
  • 刘晓林
    2019-10-29
    老师,我请教两个问题:
    1.ep_send_events_proc这个函数在把events列表拷贝到用户空间前会调用ep_item_poll函数,已确定对应的fd上的事件依旧有效。那ep_item_poll是根据什么来确定事件的有效性呢?
    2.在ep_send_events_proc处理level-triggered的时候,有这么一段话“At this point, no one can insert into ep->rdllist besides us. The epoll_ctl() callers are locked out by ep_scan_ready_list() holding "mtx" and the poll callback will queue them in ep->ovflist.”意思是说epoll_ctl()的调用者也被锁在外面了。这个锁是说在ep_send_events_proc还没处理完的时候,epoll_ctl()无法操纵rdllist,但是之后是可以的,以实现再次注册感兴趣的时间。是这样吗?
    展开

    作者回复: 看得好自信,汗,我试着回答哈:

    1.根据套接字文件上的poll接口,套接字文件上记录了它有效的事件:
    static inline unsigned int ep_item_poll(struct epitem *epi, poll_table *pt)
    {
        pt->_key = epi->event.events;

        return epi->ffd.file->f_op->poll(epi->ffd.file, pt) & epi->event.events;
    }

    2.是的。

    static int ep_scan_ready_list(struct eventpoll *ep,
                 int (*sproc)(struct eventpoll *,
                         struct list_head *, void *),
                 void *priv, int depth, bool ep_locked)
    {
        int error, pwake = 0;
        unsigned long flags;
        struct epitem *epi, *nepi;
        LIST_HEAD(txlist);

        /*
         * We need to lock this because we could be hit by
         * eventpoll_release_file() and epoll_ctl().
         */

        if (!ep_locked)
            mutex_lock_nested(&ep->mtx, depth);
            ...
    }

    
    
  • fackgc17
    2019-10-26
    可以提供一下分析用的 kernel 版本吗

    作者回复: linux 4.14.4

    
    
  • 初见
    2019-10-25
    老师,我之前面试被问到过说,epoll 更适合连接很多,但活跃的连接较少的情况

    那么,连接很多,活跃连接也很多的情况下,用什么方案呢? 堆机器嘛

    作者回复: 不知道为什么会有这样的说法,我觉得这个说法不正确,epoll适合活跃连接很多的场景。

    
    
  • 影帝
    2019-10-20
    我发现看留言学到的更多。🤓

    作者回复: 这就是social的力量 :)

    
    
  • 沉淀的梦想
    2019-10-19
    缺乏C语言和linux内核基础的人读起这些源码来相当吃力,虽然老师讲得很好

    作者回复: 主要是理解整体的概念和设计,细节不用理解太深。可以读理解几遍,肯定会有收获的。

    
    
  • TM
    2019-10-18
    hi 老师您好,有个问题想咨询下。把 redis 的 backlog 设置为 1,然后在 redis 里 debug sleep 50,然后发起两个请求,一个成功连接,另一个会出 『opration timeout』 ,而不是 connect timeout,然后大概是 26 s ,反复试了几次、都是26s左右的时间。很奇怪这个报错是内核爆出来的吗?为什么是26s这个时间呢?扩展是 phpredis,php 底层 socket 超时是 60s。

    作者回复: 你好像问过一次了吧,这个我认为不是内核报出来的,我建议你debug一下。

    
    
我们在线,来聊聊吧