系列第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已经解决了“线程等待问题”,但代码变得非常复杂。


👉 下一篇:

《协程到底解决了什么问题?》

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐