主题
I/O 多路复用:从0到1完全指南
一份面向纯小白的 Linux I/O 多路复用学习手册——从「为什么操作系统需要它」讲起,一直讲到 Redis、Nginx 是怎么用 epoll 撑起百万并发的。配套可视化演示页面与可运行 C 代码,每章末尾还附真实面试题。
0. 这份文档适合谁
- ✅ 计算机网络/操作系统刚入门,听过 select/poll/epoll 但不知道是什么的同学
- ✅ 写过 Web 项目,但好奇「Tomcat / Netty / Nginx 凭什么能扛那么多连接」的开发者
- ✅ 准备后端面试,被「epoll 原理」、「LT 与 ET 的区别」问懵的求职者
- ✅ 用 Node.js / Go / Python asyncio 写过异步代码,却不理解底层机制的工程师
生活类比开场:想象你在一家只有 1 个店员的奶茶店点单。
- 阻塞 I/O:店员一次只服务一位客人,客人没决定好喝什么,店员就一直站在那儿等——后面排队的全堵死了。
- 非阻塞 I/O 轮询:店员问完一个客人「想好了吗」,没想好就立刻去问下一个,问完一圈再回来——客人没怎么动,但店员累成狗。
- I/O 多路复用:店员吼一嗓子「谁想好了举手!」然后只去服务举手的客人——一人就能撑起一整家店的生意。
而 select / poll / epoll,就是「举手机制」的三代演进。
1. 学习路线总览
图解说明:建议严格按章节顺序阅读。第 1-2 章是地基,没有它后面看不懂;第 3-5 章是主菜,重点投入时间;第 6-8 章是升华,让你能在面试 / 实战中游刃有余。
2. 章节地图
| 章节 | 标题 | 核心问题 | 配套演示 | 配套代码 |
|---|---|---|---|---|
| 0 | README(本页) | 我该怎么学? | — | — |
| 1 | I/O 基础知识 | 什么是文件描述符?read 调用底层发生了什么? | ✅ | — |
| 2 | 五大 I/O 模型 | 阻塞、非阻塞、复用、信号、AIO 到底有什么区别? | ✅ | — |
| 3 | select 详解 | 史上第一个多路复用调用,原理与缺陷 | ✅ | ✅ |
| 4 | poll 详解 | 去掉 1024 限制后,为什么 poll 还是不够快? | ✅ | ✅ |
| 5 | epoll 深度解析 | 红黑树 + 就绪链表如何撑起百万连接?LT 与 ET 选谁? | ✅ | ✅ |
| 6 | 横向对比 | 三者性能差距在哪?什么场景选什么? | ✅ | — |
| 7 | 实战应用 | Redis、Nginx、Netty 是怎么用 epoll 的? | ✅ | — |
| 8 | 面试题集锦 | 真实大厂面试题 + 标准答案 + 追问 | — | — |
3. 知识点速览(学完应该记住的东西)
3.1 核心概念(必背)
| 概念 | 一句话定义 | 在哪一章 |
|---|---|---|
| 文件描述符(fd) | 内核给每个打开的文件/socket 分配的一个非负整数标识 | 第 1 章 |
| 用户态 / 内核态 | CPU 的两种特权级,read/write 等系统调用必须切换到内核态 | 第 1 章 |
| 阻塞 I/O | 数据没到时调用线程会被挂起,直到内核拷贝完才返回 | 第 2 章 |
| I/O 多路复用 | 一个线程同时监听多个 fd,任一就绪即返回,避免一对一阻塞 | 第 2 章 |
| select | 用位图(bitmap)传递 fd 集合,最大 1024,每次都要全量拷贝+遍历 | 第 3 章 |
| poll | 用 pollfd 数组替代位图,去掉 1024 限制,但仍是 O(n) 遍历 | 第 4 章 |
| epoll | 内核维护红黑树保存监听集合 + 就绪链表保存激活 fd,O(1) 查询 | 第 5 章 |
| LT(水平触发) | 只要 fd 上还有数据没读完,就反复通知——默认模式,不易出错 | 第 5 章 |
| ET(边沿触发) | 只在状态变化的那一刻通知一次,必须一次读完,性能高但难写 | 第 5 章 |
3.2 高频面试关键词
text
C10K 问题 Reactor 模式 惊群效应
零拷贝 Selector mmap
EPOLLONESHOT EAGAIN 非阻塞 socket
fd 表 epitem 等待队列
回调函数 水平/边沿触发 就绪链表
红黑树 惊群修复 SO_REUSEPORT学完这份文档,上面这些词你都应该能用人话解释清楚。
4. 推荐学习节奏
| 角色 | 建议时长 | 重点章节 |
|---|---|---|
| 从0到1的小白 | 5~7 天,每天 1 章 | 1 → 2 → 3 → 4 → 5(重点慢慢啃)→ 7 → 8 |
| 复习突击面试 | 1 个周末 | 直接看 5 → 6 → 8(再回头查漏 2-4) |
| 进阶/调优场景 | 按需查阅 | 6 → 7 + 第 5 章的 LT/ET 部分 |
5. 学习方法建议
- 每章必看演示页面:右上角有「🎬 可视化演示」,把抽象概念变成动图
- 每章动手跑一次代码:第 3-5 章都有完整可编译运行的 C 代码
- 生活类比 → 技术原理 → 代码实现:本系列每个核心概念都遵循这条线
- 先看「为什么需要它」再看「怎么实现」:你会发现 epoll 不是凭空出现的,每一步演化都是为了解决前一代的痛点
- 面试题不要只看答案,看追问:真实面试官会顺着你的回答继续深挖
6. 参考资料
| 类型 | 资源 | 说明 |
|---|---|---|
| 📖 经典书 | 《UNIX 网络编程 卷1:套接字》 W.Richard Stevens | 多路复用的圣经,第 6 章是必读 |
| 📖 经典书 | 《Linux 高性能服务器编程》 游双 | 国人写的,epoll 章节通俗易懂 |
| 📖 内核源码 | fs/select.c、fs/eventpoll.c | 想看 epoll 真实实现就读它 |
| 🌐 官方文档 | man 2 select / man 2 poll / man 7 epoll | 系统调用最权威的文档 |
| 🌐 经典文章 | The C10K problem | Dan Kegel 1999 年的雄文,多路复用的起源 |
| 💻 项目源码 | Redis ae_epoll.c、Nginx ngx_epoll_module.c | 工业级 epoll 用法的范本 |
下一站 → 第 1 章:I/O 基础知识,先把"用户态/内核态"和"文件描述符"两块地基打牢,后面才学得动。