zoukankan      html  css  js  c++  java
  • select,poll,epoll总结

    还在持续学习中,本文是一个阶段性的总结。

    一、select

    select的核心是不停的遍历文件描述符,看看是否就绪。一般最多同时支持1024个文件描述符。

    1.1 select函数

    int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
    
    1. nfds:最大的文件描述符加1
    2. readfds:监听可读集合
    3. writefds:监听可写集合
    4. exceptfds:监听异常集合
    5. timeout:超时时间

    1.2 select流程

    唤醒 当前进程的过程通常是在所监测文件的设备驱动内实现的,驱动程序维护了针对自身资源读写的等待队列。当设备驱动发现自身资源变为可读写并且有进程睡眠在该资源的等待队列上时,就会唤醒这个资源等待队列上的进程。

    1.3 select问题

    1. 每次调用时要重复地从用户态读入参数。
    2. 每次调用时要重复地扫描文件描述符,遍历所有文件描述符。
    3. 每次在调用开始时,要把当前进程放入各个文件描述符的等待队列。在调用结束后,又把进程从各个等待队列中删除
    4. 对文件描述符的数量有限制(一般为1024个)

    select随着文件描述符数量的上升,性能会急剧下降

    二、poll

    poll的整体流程和select差不多,也是每次遍历所有文件描述符,性能不好,不过poll解决了select文件描述符数量的限制问题。

    三、epoll

    select和poll运行效率的两个瓶颈已经找出,现在的问题是怎么改进。

    1. 首先,如果要监听1000个fd,每次poll都要把1000个fd 拷入内核,这是极大的浪费,内核干嘛不自己保存已经拷入的fd呢?**epoll就是自己保存拷入的fd **,它的API就已经说明了这一点,不是 epoll_wait的时候才传入fd,而是通过epoll_ctl把所有fd传入内核再一起"wait",这就省掉了不必要的重复拷贝。
    2. 其次,在 epoll_wait时,也不是把current轮流的加入fd对应的设备等待队列,而是在设备等待队列醒来时调用一个回调函数(当然,这就需要“唤醒回调”机制),把产生事件的fd归入一个链表,然后返回这个链表上的fd。
    3. 另外,epoll机制实现了自己特有的文件系统eventpoll filesystem

    3.1 epoll 函数

    epoll总共提供了三个函数

    1. int epoll_create(int size);
      

    epoll_create是为了创建一个epoll文件描述符,新创建的epoll文件描述符带有一个struct eventpoll结构,eventpoll结构如下。

    struct eventpoll {  
        spinlock_t lock;  
        struct mutex mtx;  
        wait_queue_head_t wq;  /* Wait queue used by sys_epoll_wait() ,调用epoll_wait()时, 我们就是"睡"在了这个等待队列上*/
        wait_queue_head_t poll_wait;  /* Wait queue used by file->poll() , 这个用于epollfd本事被poll的时候*/
        struct list_head rdllist; /* List of ready file descriptors, 所有已经ready的epitem都在这个链表里面*/ 
        struct rb_root rbr; /* RB tree root used to store monitored fd structs, 所有要监听的epitem都在这里*/ 
        epitem *ovflist;  /*存放的epitem都是我们在传递数据给用户空间时监听到了事件*/.
        struct user_struct *user; /*这里保存了一些用户变量,比如fd监听数量的最大值等*/  
    };  
    

    这个结构上再挂一个红黑树,而这个红黑树就是每次epoll_ctl时fd存放的地方。

    1. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
      

    此函数是添加、删除、修改事件

    1. int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
      

    此函数是等待条件满足,返回值为准备就绪的事件数

    3.2 epoll 流程


    参考
    1.https://www.cnblogs.com/Anker/p/3265058.html
    2.https://blog.csdn.net/weixin_42462202/article/details/95315926
    3.https://blog.csdn.net/turkeyzhou/article/details/8609360
    4.http://blog.chinaunix.net/uid-20643761-id-1594860.html
    5.http://blog.chinaunix.net/uid-28541347-id-4236779.html
    6.http://blog.chinaunix.net/uid-28541347-id-4238524.html

  • 相关阅读:
    Oracle创建上下文 SYS_CONTEXT
    闪回版本查询
    物化视图创建案例
    Oracle 多租户环境学习路线图
    【Mysql MHA】CentOS7.6+Mysql8.0.16 入坑
    【翻译】--19C Oracle 安装指导
    Docker(3)---常用命令
    Docker(2)---安装(设置镜像加速器)
    Docker(1)---基础概念
    AMQP高级消息队列协议
  • 原文地址:https://www.cnblogs.com/Brake/p/14083663.html
Copyright © 2011-2022 走看看