你好,我是吴计可师,一个工作十多年的后端开发,曾就职京东、阿里等多家互联网头部企业。
文章可能会比较长,主要解析的非常详解,或涉及一些底层知识,供面试高阶难度用。可以根据自己实际理解情况合理取舍阅读
I/O多路复用机制 是一种高效的网络通信技术,允许程序同时监听多个 I/O 事件,提高系统对高并发请求的处理能力。它主要解决 单线程无法高效处理多个连接 的问题,在网络编程中至关重要。
I/O多路复用指通过一个或多个系统调用,使一个线程可以监控多个文件描述符(文件、套接字等)的 I/O 事件(如读、写、异常),一旦有事件就绪,程序可以进行相应处理。
本质:让单个线程高效地处理多个 I/O 连接。
关键优势:无需为每个连接创建一个线程或进程,节省资源,提高并发性能。
工作原理:
使用一个位图表示所有监听的文件描述符。
每次调用 select,内核会遍历所有文件描述符,检查哪些就绪。
优点:跨平台,简单易用。
缺点:
每次调用都需要遍历所有 fd,效率低,时间复杂度 O(n)。
文件描述符有上限(默认 1024)。
工作原理:
使用一个链表存储所有文件描述符和监听的事件。
内核遍历链表检查就绪的文件描述符。
优点:没有文件描述符数量限制。
缺点:同样需要遍历所有 fd,效率较低。时间复杂度仍为 O(n)。
工作原理:
采用 事件驱动机制,将文件描述符和事件注册到内核,内核维护就绪事件。
使用一个红黑树管理监听的文件描述符,就绪队列存储触发的事件。
事件通知机制,避免遍历所有文件描述符。
支持 水平触发(LT) 和 边缘触发(ET)。
优点:
效率高,时间复杂度接近 O(1)。
支持大量并发连接,性能优越。
缺点:Linux 特有,代码复杂度略高。
kqueue:FreeBSD 系统的 I/O多路复用机制,与 epoll 类似,提供高效事件通知。
IOCP(I/O Completion Port):Windows 平台的高效 I/O 机制,基于异步事件通知。
传统线程/进程:
为每个 I/O 连接创建一个线程或进程,占用大量系统资源。
上下文切换开销大,效率低。
I/O多路复用:
单线程可同时处理多个连接,减少线程数量和上下文切换开销。
更适合高并发场景。
高并发网络服务器:Nginx、Redis、Netty 等框架使用 epoll 进行 I/O 多路复用。
即时通讯系统:需要监听大量连接的实时消息传输。
长连接场景:大量用户维持长连接,比如聊天室、WebSocket 等。
水平触发(Level Triggered, LT):
只要文件描述符上的 I/O 事件还未被处理,系统会持续通知应用程序。容易处理,但可能导致重复通知。
边缘触发(Edge Triggered, ET):
只有在文件描述符的状态发生变化时,系统才会通知应用程序。
更高效,但要求程序确保一次性处理完所有数据。
事件驱动:epoll 使用事件通知机制,避免轮询所有文件描述符。
时间复杂度:epoll 的时间复杂度接近 O(1),而 select 和 poll 为 O(n)。
无文件描述符限制:epoll 不受文件描述符数量限制。
就绪队列:epoll 维护一个就绪队列,只返回就绪的事件,减少了数据拷贝。
epoll_create:创建一个 epoll 实例,返回一个文件描述符。
epoll_ctl:对文件描述符执行操作(添加、删除、修改)。
EPOLL_CTL_ADD:添加事件。
EPOLL_CTL_DEL:删除事件。
EPOLL_CTL_MOD:修改事件。
epoll_wait:等待事件发生,并返回就绪的事件。
红黑树:存储所有被监控的文件描述符和事件,方便快速增删改查。
就绪队列:存储已经触发的事件,epoll_wait 直接返回就绪事件,避免遍历。
select:适合小规模连接,跨平台简单实现。
poll:适合中等规模连接,较 select 改进,无文件描述符上限。
epoll:适合大规模高并发场景,Linux 环境下首选。
实际应用:
Nginx 和 Redis 使用 epoll。
跨平台网络库可能基于 select/poll 实现。
今天的内容就分享到这儿,喜欢的朋友可以关注,点赞。有什么不足的地方欢迎留言指出,您的关注是我前进的动力!