I/O 多路复用:select/poll/epoll 实现原理及区别

简介: I/O 多路复用:select/poll/epoll 实现原理及区别

参考文章:9.2 I/O 多路复用:select/poll/epoll


I/O 多路复用 $\color{red}{★}$

多路复用:一个 线程/进程 处理多个io事件流的请求。
select/poll/epoll内核提供给用户态的多路复用系统调用,进程可以通过一个系统调用函数从内核中获取多个事件。

select/poll/epoll是如何获取网络事件的呢?
在获取事件时,先把所有连接(文件描述符集合)传给内核,再由内核返回产生了事件的连接,最后在用户态中处理这些连接对应的请求即可。

selectpoll实现多路复用的方式及区别

两者并没有本质区别,它们内部都是使用「线性结构」来存储进程关注的 Socket 集合。

方式

  1. 在使用时,首先要把关注的 Socket 集合通过 select/poll 系统调用从用户态拷贝到内核态
  2. 然后由内核检测事件,当有网络事件产生时,内核需要遍历进程关注的 Socket 集合,找到有事件产生的 Socket,并将其状态标记为 可读/可写
  3. 然后把整个 Socket 集合从内核态拷贝到用户态,用户态还要再次遍历整个 Socket 集合找到被标记为 可读/可写 的 Socket,然后对其处理。

区别

  • select使用 BitsMap位图 的方式存储 fd_set,支持的文件描述符个数受限(由linux内核中的 FD_SETSIZE 限制),默认为 1024,只能监听 0~1023 的文件描述符。
  • poll则使用动态数组的方式存储 fd_set,以链表形式来组织。突破了 select 中文件描述符的个数限制,当然还是会受到系统文件描述符个数限制

缺点
很明显发现,selectpoll的缺陷在于:当客户端越多,也就是 Socket 集合越大,Socket 集合的2次遍历(时间复杂度为 O(n))和2次拷贝会带来很大的开销

此方式随着并发数上来,性能的损耗会呈指数级增长,因此也很难应对 C10K问题(即单机1万个并发连接)。

epoll实现多路复用的方式及区别

epoll是解决 C10K 问题的利器,通过两个方面解决了 select/poll的问题。

  • epoll在内核里使用「红黑树」来关注进程所有待检测的 Socket。红黑树是个高效的数据结构,增删改一般时间复杂度是 O(logn)。

通过对这棵黑红树的管理,不需要像 select/poll在每次操作时都传入整个 Socket 集合,而只需要传入一个待检测的 socket减少了内核和用户空间大量的数据拷贝和内存分配

  • epoll 使用事件驱动(回调函数)的机制,内核里维护了一个「链表」来记录有事件产生的就绪事件。

只将有事件发生的 Socket 集合传递给用户态应用程序,不需要像 select/poll 那样轮询整个集合(包含有事件和无事件的 Socket ),大大提高了检测的效率。

而且,epoll支持边缘触发(产生事件时,仅通知一次)和水平触发(产生事件时,一直通知)的方式,而 select/poll只支持水平触发。一般而言,边缘触发的方式会比水平触发的效率高。

目录
相关文章
|
2月前
|
Java
如何理解网络阻塞 I/O:BIO
如何理解网络阻塞 I/O:BIO
|
2月前
|
消息中间件 Kubernetes NoSQL
Reactor 和 Proactor 区别
Reactor 和 Proactor 区别
|
12天前
|
存储 安全 网络协议
epoll的底层实现原理
epoll的底层实现原理
25 0
|
2月前
|
数据采集 Python
Python多线程与异步IO的对比:何时选择哪种并发模型
Python多线程与异步IO的对比:何时选择哪种并发模型
132 1
|
2月前
|
存储 安全 网络协议
epoll的实现原理
epoll的实现原理
44 0
|
8月前
|
存储 监控 安全
2.9 epoll的实现原理
2.9 epoll的实现原理
46 0
|
11月前
|
Linux
网络编程之阻塞与非阻塞的理解
网络编程之阻塞与非阻塞的理解
80 0
|
存储 监控 NoSQL
epoll底层原理
epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本。
376 0
epoll底层原理
|
Linux
Linux网络编程之阻塞与非阻塞
Linux网络编程之阻塞与非阻塞
175 0
Daz
|
Linux 程序员 API