• epoll的由来


    reference 

    https://www.zhihu.com/question/20122137

    感谢 @静海听风 @蓝形参

    数据流有两个重要的参与者:

    1、往流中写入数据者

    2、从流中读取数据者

    假设两个参与者之间,使用一个缓冲区来存放数据,即a往缓冲区中写入数据,b从缓冲区中读出数据。那么对单个流而言,会存在四种状态:

    0、当缓冲区为空时,b阻塞,等待数据到达;

    1、当a往缓冲区写入数据时,缓冲区非空,b将被从阻塞状态中唤醒;

    2、当a拼命往缓冲区中写入数据,而b没有去读,或读的速度跟不上a写入的速度时,缓冲区满。此时,需要通知a进行阻塞,等待缓冲区中重新腾出空间;

    3、当b从缓冲区中读出部分数据后,缓冲区非满,则可以通知a从阻塞状态中醒来;

    4、当a不再往缓冲区中写数据,而b一直读,将缓冲区中的数据读完时,将变成缓冲区空,此时通知b进入阻塞状态,等待有数据到来。

    当有多个流时,可以考虑用轮训的方式逐一查看每个流目前是否有数据,若有,则进行处理。(非阻塞轮询--一直主动查看流的状态)

    缺点:cpu空耗在无用的流缓冲区检查上,浪费时间。

    改进:引入一个代理人(select),当代理人感知到有一个或多个流的数据有变化时,再进行轮询检查。(非阻塞轮询--有流的状态发生变化时,主动检查所有流的状态)

    缺点:当只有一个或少数流有更新时,遍历检查所有的流非常浪费时间。(故,亦称为无差别轮询)

    改进:当有流的状态改变时,仅处理该流相关的数据变化。(epoll--event poll,事件轮询,精确到“什么流”发生了“什么事件”)

    具体实现是引入了一个红黑树及一个就绪列表。

    epoll的关键操作:

    1、创建一个epoll对象

    epollfd=epoll_create()

    此时,会在内核中专属于epoll的高速cache区新建一棵红黑树以及一个就绪列表

    2、往epoll中添加或删除某个流某个事件

    epoll_ctl(epollfd, EPOLL_CTL_ADD, socket, EPOLLIN)

    epoll_ctl(epollfd, EPOLL_CTL_DEL, socket, EPOLLOUT)

    "add"动作会将文件句柄(socket)加入到红黑树中,并向内核注册改句柄的回调函数,当内核检测到该句柄可读或可写时(由中断触发),就将该句柄对应的回调函数加入到就绪列表中。

    3、等待事件发生

    epoll_wait(epollfd,...)

    epoll_wait函数只需要关注就绪列表即可。

    当就绪列表中有就绪的socket时,就将这些socket拷贝到用户态,并清空就绪列表。

    而后,还会检查这些socket的触法形式(水平出发or边缘触法)

    若是水平触发(lt),则若这些socket中还有未处理的事件时,就再把它们加回到就绪列表中;

    若是边缘触发(et),则只有当下一次中断到达时,才会把这个socket加回到就绪列表中。

    从伪代码上可以更明显的看出三种轮询的区别:

    无阻塞忙轮询:

    while true{

      for i in stream[]{

        if i has data

          read until unavailable

      }

    }


    无阻塞轮询(无差别轮询):

    while true{

      select(stream[])

      for i in stream[]{

        if i has data

          read until unavailable

      }

    }

    事件轮询(epoll):

    while true{

      active_stream[] = epoll_wait(epollfd)

      for i in active_stream[]{

        read or write until unavailable

      }

    }

  • 相关阅读:
    Sublime Text安装Package Control
    HTTP,FTP,TCP,UDP及SOCKET
    Oracle数据库的导入导出
    C#.NET中数组、ArrayList和List三者的区别
    一道有趣的逻辑面试题(数独)
    C#常用命名空间
    C# Dictionary已知value获取对应的key
    C#记录程序耗时的方法
    有return语句情况下,try-catch-finally的执行顺序
    C# 拷贝数组的几种方法
  • 原文地址:https://www.cnblogs.com/elaron/p/7048060.html
Copyright © 2020-2023  润新知