select/poll/epoll

文章探讨了阻塞和非阻塞IO的区别,指出了阻塞IO在高并发情况下的线程资源限制。介绍了轮询检索和回调通知两种策略,并详细阐述了select、poll和epoll在Linux中的作用,特别是epoll作为高效I/O多路复用机制,适合高并发场景。epoll利用回调通知和红黑树数据结构优化了文件描述符的管理,支持边沿触发和水平触发模式,提高了性能。
摘要由CSDN通过智能技术生成

阻塞与非阻塞

阻塞与非阻塞区别在于,前者必须等待数据后才可继续执行。后者则是若没有数据,则立即返回继续执行。

下面为一个简单的描述阻塞IO的时序图:

阻塞IO的时序图

缺点显而易见,每个请求都需要对应一个线程。而线程数也是存有上限的,因为内存空间有限。所以当并发量大时,可以处理请求量等价于可建线程数。

轮询检索与回调通知

  1. 轮询检索:对元素列表顺序迭代检索,从而得到需要的元素,复杂度为 O(n)。

  2. 回调通知:在元素列表中添加元素时,同时注册一个回调函数,并将就绪元素列表作为参数传递进去。当元素转为就绪态时,调用该回调方法将自身加入到就绪元素列表。元素主动性的添加,使得获取就绪元素时的复杂度降为了O(1)。

selec / poll / epoll 概述

select、poll 和 epoll 是 Linux 操作系统中用于异步 I/O 操作的三种不同机制。

select() 是一个系统调用,用于监视多个文件描述符,等待其中一个或多个变为特定类型的 I/O 操作。它操作的是一个由 fd_set 结构组成的数组,其中每个结构表示要监视的一组文件描述符。Select 是这三种机制中最基本和最便携的,但在可扩展性方面还有一些限制。

poll() 与 select() 类似,但它使用的是一个 struct pollfd 结构的数组,而不是 fd_set 结构。此外,poll() 还提供了一些额外的功能,如为轮询操作设置超时和监视文件描述符上的错误。

epoll() 在 Linux 2.5.44 中作为对 poll() 和 select() 的更可扩展替代方案引入。epoll 是一种事件驱动的I/O模型,它是Linux内核中实现高效的I/O多路复用的机制之一。使用epoll可以监控大量的文件描述符,当其中任意一个文件描述符上有读、写、异常等事件发生时,就会触发相应的回调函数来处理这些事件,从而实现高效的I/O操作。
另外,epoll还支持边沿触发(ET)和水平触发(LT)两种工作模式。在LT模式下,只要该文件描述符上有数据可读或可写,就会立即返回通知应用程序进行处理;而在ET模式下,仅当文件描述符状态发生变化时才会返回通知,这可以减少 epoll_wait 调用次数,提高效率。例如对于读事件 EPOLLIN:ET模式下,一定要及时处理干净本次的数据,否则后面不一定会继续通知导致数据丢失。而LT模式下,只要 Socket 上有未读完的数据,EPOLLIN 就会一直触发。

总结:select() 和 poll() 适用于需要监视少量文件描述符的应用程序,而 epoll() 则更适合具有高并发性和可扩展性要求的应用程序。所以,epoll 也是我们下面要详细介绍的内容。

select / poll

select / poll 对监控的Socket文件描述符采用的为轮询检索,大体流程如下:

  1. 应用程序向内核注册一组文件描述符以及感兴趣的事件类型(如可读、可写等)。
  2. 应用程序调用 select 或 poll 等待其中任意一个文件描述符上发生感兴趣的事件。
  3. 内核对每个注册的文件描述符都进行轮询,判断是否有相应的事件发生。如果有,则将该文件描述符标记为就绪状态,并将其返回给应用程序。
  4. 应用程序根据返回的就绪文件描述符进行相应的操作。
  5. 回到步骤 2,重复执行以上过程。

轮询的缺点很明显:当需要管理的文件描述符数量很大时,轮询的开销会非常大,导致性能降低。
关于 select / poll 的其他内容,如最大容量等、二者差异就不过多介绍,不是核心点。

epoll

epoll 对监控的Socket文件描述符采用的是回调通知的方式。epoll 是 select / poll 的增强。分为三个函数:epoll_create、epoll_ctl、epoll_wait。函数功能如下:

  1. epoll_create:创建一个 epoll 实例。该调用返回一个文件描述符,可以用于后续的 epoll 操作。
  2. epoll_ctl:将要监听的 socket 注册到 epoll 实例上。需要指定监听的socket文件描述符、监听事件类型以及对应的回调函数等信息。
  3. epoll_wait:等待监听的事件发生。如果有事件发生,epoll_wait() 将返回一个包含事件信息的事件列表。
epoll 在内核源码中的定义

结构体:

// fs/eventpoll.c
struct eventpoll {
    // 阻塞在epoll_wait函数的用户进程等待队列
    wait_queue_head_t wq;
    // 就绪的 socket 文件描述符的列表 (被包装为epitem)
    struct list_head rdllist;
    // 存放添加的需要监听的 socket 文件描述符的红黑树 (被包装为epitem)
    struct rb_root rbr;
    ......
}

示意图:
在这里插入图片描述

epoll 应用时序图

epoll 应用时序图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值