select、poll和epoll的区别

select、poll和epoll的区别。小编来告诉你更多相关信息。select、poll和epoll的区别今日小编为你讲解select、poll和epoll的区别的IT知识,接下来小编为大家介绍。我们

select、poll和epoll的区别。小编来告诉你更多相关信息。

select、poll和epoll的区别

今日小编为你讲解select、poll和epoll的区别的IT知识,接下来小编为大家介绍。

我们从源码的角度看一下它们实现有哪些区别。

select:客户端操作服务器时会生成三种文件描述符 fd:readfds(读)、writefds(写)和 exceptfds(异常)。

int select(int maxfd,   fd_set *readset,   fd_set *writeset,   fd_set *exceptset,   struct timeval *timeout);返回值:   Ready_fd -> Ready_fd num // 当调用select时,返回就绪的fd数量   Timeout -> 0 // 超时返回0   Error -> -1 // 错误返回-1

遍历函数 select() 执行时,会阻塞当前线程(老师啥也不做,等着看哪个学生举手了),以监视这 3 类文件描述符,等有数据可读、可写或者产生异常时,就会返回。返回后通过遍历 fdset 整个数组来找到已就绪的 fd,然后进行相应的 IO 操作。

优点:几乎所有的平台都支持;

缺点:

  • 单个进程打开的 fd 限制数量为 1024 个(32位机器),可通过宏定义修改,但是效率依旧很慢;
  • 每次调用 select() 时,需要把 fd 数据从用户态拷贝到内核态,频繁复制开销很大;
  • 轮询方式遍历,会随着套接字 fd 的数量增多,性能下降。且每次都需要全部遍历,浪费CPU 时间,时间复杂度为 O(n)。

poll:基本原理与 select 一致,也是轮询 + 遍历,区别是 poll 中 fd 没有最大数量的限制(使用链表的方式存储 fd)。

int poll (struct pollfd *fds, // 链表存储   unsigned long nfds,   int timeout);返回值:   Ready_fd -> Ready_fd num   Timeout -> 0   Error -> -1   struct pollfd {   int fd; // file descriptor,文件描述符   short events; // events to look for,不变   short revents; // events returned,返回}

epoll:没有 fd 个数限制,且 fd 集合从用户态到内核态只需要一次,使用时间通知机制来触发。通过 epoll_ctl 注册 fd,一旦 fd 就绪就会通过回调地址来激活对应的 fd,进行相关的 IO 操作。

int epoll_create(int size);int epoll_ctl (int epfd,   int op,   int fd,   struct epoll_event *event);int epoll_wait (   int epfd,   struct epoll_event *events,   int maxevents,   int timeout)   typedef union epoll_data {   void *ptr;   int fd;   uint32_t u32;   uint64_t u64;}epoll_data_t;struct epoll_event {   uint32_t events;   // epoll events   epoll_data_t data; // user data variable}

epoll 之所以性能高是得益于它的三个函数:

  • epoll_create() 系统启动时,在 Linux 内核里创建 epoll 实例(申请一个红黑树 rbTree 和就绪链表 readyList),以便存放 socket 节点;
  • epoll_ctl() 每新建一个连接,都通过该函数操作 epoll 对象,在这个对象的红黑树里增、删、改对应的 socket 节点,绑定一个回调函数;

    select、poll和epoll的区别。小编来告诉你更多相关信息。

    select、poll和epoll的区别

  • epoll_wait() 轮询所有的回调集合,并完成对应的 IO 操作。相应分三步:
    • 阻塞线程
    • 内核查找红黑树中准备好的 socket,放入就绪链表 rdlist
    • 就绪列表中的内容复制到 events(从内核态复制到用户态),准备循环处理这些已就绪的 socket 节点

示例:

int fds[] = ...;int efd = epoll_create(...); //内核态创建epoll实例(包含红黑树rbTree和就绪链表readyList)for (int i=0; i0) {       for (i=0; i<n; i++) {           events[i].data.fd; // 这里有所有需处理的socket,不需要像select和poll那样全部遍历      }  }}

优点:

  • 没有 fd 限制,所支持的 fd 上限时操作系统的最大文件句柄数,1G 内存大概支持 10 万个句柄;
  • 效率高,采用回调通知而不是轮询的方式,即使 fd 数目增加,时间复杂度仍为 O(1);
  • 用户与内核空间基于一种内存映射文件的方法,使它们可以共享内存空间,减少文件从用户态移动到内核态带来的性能消耗。

select、poll和epoll的区别

LT 和 ET:

  • LT,level triggered,水平触发,又叫条件触发。当被监控的 fd 上有可读写的事件时,epoll_wait() 会通知处理程序去读写。如果这次没有把数据一次性全部读写完,那么下次调用 epoll_wait() 时,它还会通知你上次没有读写完的 fd,可继续读写。而且我们不需要读写的 fd,它也会一直通知你。
  • ET,edge triggered,边缘触发。当被监控的 fd 上有可读写事件时,epoll_wait() 会通知处理程序去读写。如果这次没有把数据全部读完,下次将不再通知。
  • 学过计算机组成原理的应该知道脉冲信号,其实 ET 和 LT 的原理和电信号的变化差不多。LT 就是只有高电平(1)或低电平(0)时才触发通知,只要在指定的状态上,就会得到通知;ET 是只有电平发生变化时(从高电平到低电平,或者从低到高),才触发通知。

三者实践对比:

例如,100w 个连接,里面有 1w 个活跃连接。

select:不修改宏定义时,默认把 1024 个 fd 放到同一个进程。则需要 100w/1024 = 977 个进程才可以支持,会使得 CPU 性能特别差;

poll:没有最大文件描述符限制,100w 个连接则需要 100w 个 fd,遍历特别慢不说,还有空间拷贝还会消耗大量的资源;

epoll:请求进来时就创建 fd 并绑定一个回调地址,当活跃连接发起请求 IO 操作时,epoll_wait() 函数只需要遍历这 1w 个活跃连接,进行相应的额操作即可,既高效又不用做内存拷贝。

本文分享的select、poll和epoll的区别的相关内容,供网友参考,希望能解决您的问题。

本文内容由互联网用户自发贡献,该文观点仅代表作者本人。如发现本站有涉嫌抄袭侵权/违法违规的内容,请发送邮件至 5733401@qq.com 举报,一经查实,本站将立刻删除。本文链接:https://fajihao.com/i/256172.html

(0)
恰卡的头像恰卡
上一篇 2023-11-06
下一篇 2023-11-06

相关推荐