IO多路复用 & epoll 面试完整版
一、基础概念
1. 什么是 IO 多路复用
IO 多路复用 :一个线程通过单个系统调用 ,同时监听多个文件描述符(FD),当任意一个 FD 有可读/可写/异常事件时,内核通知线程,线程再去处理对应 IO。
核心价值:单线程高效管理大量连接,避免多线程模型的线程创建、切换、锁竞争开销,是高并发网络服务的核心基础。
常见实现:Linux 下 select、poll、epoll;Windows 下 IOCP。Redis、Nginx、Tomcat 均基于该技术。
2. epoll 详细原理(Linux 主流实现)
epoll 是 Linux 高性能 IO 多路复用模型,分为水平触发(LT) 、边缘触发(ET),整体分三步使用:
(1)三大核心系统调用
-
epoll_create
创建一个 epoll 实例,返回 epoll 文件描述符,内核会分配专属内存空间,用于存放待监听的 FD 和事件。
-
epoll_ctl
向 epoll 实例增/删/改 要监听的文件描述符(比如客户端连接 Socket),并绑定监听事件(读、写、异常)。
内核会把这些 FD 挂载到红黑树 中管理,同时维护一个就绪链表,专门存放已经产生事件的 FD。
-
epoll_wait
线程阻塞等待事件,内核扫描就绪链表,直接把已经就绪的 FD 列表返回给用户态线程。线程遍历列表,逐个处理 IO 读写。
(2)两大触发模式
- 水平触发 LT(默认) :只要 FD 还有数据未读完,每次
epoll_wait都会持续通知,兼容性好,Redis 默认使用。 - 边缘触发 ET :仅在状态第一次变化时通知一次,必须一次性把数据读完,要求代码严谨,性能略高。
(3)相比 select/poll 的核心优势
- 文件描述符无上限:select 有最大 FD 限制,epoll 仅受系统资源限制;
- 时间复杂度更低:select/poll 遍历全部 FD(O(n)),epoll 只遍历就绪 FD(O(1));
- 内存拷贝优化:epoll 采用内存映射,减少用户态与内核态之间的数据拷贝开销。
二、标准面试口述回答(分版本,直接背诵)
版本1(常规完整版,面试通用)
IO 多路复用是用一个线程监听多个IO连接,有事件到达再进行处理,提升并发能力。
Linux 下主流实现是 epoll,它通过 epoll_create 创建实例,epoll_ctl 管理监听的文件描述符,内核用红黑树维护所有监听FD、就绪链表存放有事件的FD;最后通过 epoll_wait 阻塞获取就绪事件。
epoll 分为水平触发和边缘触发,相比 select/poll,它没有连接数上限,且只遍历就绪连接,高并发场景性能优势明显,Redis、Nginx 等高并发中间件都基于 epoll 实现网络模型。
版本2(精简版,短问答使用)
IO多路复用让单线程监听多个网络连接。epoll 是Linux高性能实现,依靠红黑树管理监听连接、就绪链表返回事件,时间复杂度低、连接数无上限,支持两种触发模式,是高并发服务的底层网络基础。
三、一句话总结(收尾必背)
epoll 是 Linux 下高性能 IO 多路复用实现,依靠内核红黑树与就绪链表,让单线程高效监听海量网络连接,支撑高并发网络服务。