为什么会出现Reactor?IO模型的本质(从线程到协程 · 第3篇)
系列第3篇|承接上一篇《线程池解决了什么?为什么还不够?》
本篇讲清楚:为什么线程池在高并发IO下仍然不够 → Reactor如何解决
一、先说结论(一定要记住)
👉 Reactor的核心思想只有一句话:
不要让线程等,等事件就绪再处理
二、线程池为什么在IO场景下不够用?
场景:高并发请求
1000个请求同时进来
↓
每个请求都要访问数据库 / 网络
↓
每个线程执行 IO 操作
❌ 传统线程池模型
线程1:发请求 → 等IO → 阻塞
线程2:发请求 → 等IO → 阻塞
线程3:发请求 → 等IO → 阻塞
...
👉 结果:
线程全部卡住(等待IO)
CPU空闲(但线程被占用)
👉 本质问题:
线程被“等待”浪费了
三、IO到底在干嘛?(本质理解)
一个IO操作,本质是:
发请求 → 等待数据返回 → 处理数据
👉 关键点:
等待阶段(最耗时)
CPU不参与
👉 举个例子:
发送网络请求:1ms
等待响应:100ms
处理数据:1ms
👉 你会发现:
98%时间在“等”,不是在“算”
四、传统模型的问题在哪里?
传统模型是:
一个请求 = 一个线程
👉 但问题是:
线程在等IO时 → 什么都不干
👉 如果:
1000个请求 → 1000个线程
👉 就变成:
1000个线程在“发呆”
👉 所以问题不是:
线程不够
👉 而是:
线程被浪费
五、IO模型的演进(核心)
1️⃣ 阻塞IO(Blocking IO)
read(fd)
↓
没有数据 → 阻塞
线程必须等
2️⃣ 非阻塞IO(Non-blocking IO)
read(fd)
↓
没有数据 → 立即返回
👉 你要不停轮询:
while(true) {
read(fd);
}
👉 问题:
CPU空转(浪费)
3️⃣ IO多路复用(epoll / select)
👉 核心:
让操作系统帮你等
epoll_wait()
↓
哪些fd有数据 → 返回
👉 你只处理:
ready 的连接
本质:
等待交给OS,处理交给线程
六、Reactor模型是什么?
👉 Reactor = IO多路复用 + 事件驱动
核心结构
Reactor
↓
监听事件(epoll)
↓
事件就绪
↓
分发给Handler处理
👉 简化流程:
1. 注册连接(fd)
2. 等待事件(epoll_wait)
3. 哪个fd ready
4. 调用对应处理逻辑
👉 图示:
[Client1] ─┐
[Client2] ─┼──> Reactor(epoll)──> Handler
[Client3] ─┘
七、Reactor解决了什么问题?
1️⃣ 不再一个连接一个线程
从:1000连接 = 1000线程
👉 变成:
1000连接 = 少量线程 + epoll
2️⃣ 不再阻塞等待
👉 原来:
线程等IO
👉 现在:
线程只在“有数据时”执行
3️⃣ 极大提高线程利用率
👉 线程只做:
处理数据
👉 不再做:
等待
八、Reactor的本质(非常重要)
👉 Reactor不是“新技术”,而是: 调度策略升级
👉 原来:
线程驱动任务
👉 现在:
事件驱动任务
👉 本质变化:
谁来触发执行?
| 模型 | 触发方式 |
|---|---|
| 多线程 | 线程调度 |
| Reactor | 事件就绪 |
九、Reactor vs 线程池
| 维度 | 线程池 | Reactor |
|---|---|---|
| 模型 | 任务驱动 | 事件驱动 |
| IO处理 | 阻塞 | 非阻塞 |
| 线程利用率 | 低 | 高 |
| 并发能力 | 中 | 高 |
👉 一句话总结:
线程池优化线程,Reactor优化IO
十、Reactor的局限性(很关键)
1️⃣ 编程复杂
回调地狱
状态机复杂
代码难维护
2️⃣ 不是“同步思维”
onRead → onWrite → callback
👉 不直观
3️⃣ 业务代码难写
逻辑被拆碎
👉 所以:
Reactor解决了性能问题,但带来了复杂度问题 (后面协程就是为了解决这个问题)
十一、为什么会出现协程?(铺垫下一篇)
👉 你会发现:
线程池 → 简单,但浪费线程
Reactor → 高效,但复杂
那有没有一种方式:
既不阻塞线程
又能写同步代码?
👉 答案是:
协程
👉 本质:用“同步写法”表达“异步执行
十二、统一模型(必须记住)
多线程:任务 = 线程
线程池:复用线程
Reactor:事件驱动
协程:任务调度
👉 再压缩一句:
Reactor解决“线程等待问题”,协程解决“代码复杂度问题”
十三、面试标准回答
Reactor模型主要是为了解决高并发IO场景下线程被阻塞的问题。在传统线程模型中,一个连接通常对应一个线程,当IO操作发生时,线程会阻塞等待,导致大量线程资源被浪费。
Reactor通过IO多路复用机制(如epoll),将多个连接注册到一个事件监听器上,当某个连接有数据就绪时再进行处理,从而避免线程在等待IO时被占用。
本质上,Reactor是将“线程驱动”转为“事件驱动”,从而提升线程利用率和系统吞吐能力。
十四、总结
👉 到这里你会发现:
Reactor已经解决了“线程等待问题”,但代码变得非常复杂。
👉 下一篇:
《协程到底解决了什么问题?》
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)