AI生成,未完全消化……
一、Reactor 模式(反应器模式)
核心思想:基于 “事件驱动”,通过一个集中式的事件循环等待事件发生,再将事件分发给对应的处理器处理。其核心是 “等待事件→分发处理” 的同步触发机制。
1. 核心组件
-
事件源(Event Source):产生事件的实体,如网络套接字(socket)、文件描述符(fd)等。
-
事件多路分发器(Event Multiplexer):监听事件源,当事件就绪时通知反应器(如 Linux 的
epoll、poll,Windows 的select)。 -
事件处理器(EventHandler):定义事件处理接口(如
handleRead()、handleWrite()),由具体业务逻辑实现。 -
反应器(Reactor):协调事件多路分发器和事件处理器,负责注册 / 注销事件、分发就绪事件。
2. 工作流程
-
应用程序向 Reactor 注册事件(如 “读就绪”)及对应的处理器;
-
Reactor 通过事件多路分发器阻塞等待事件就绪;
-
当事件就绪(如 socket 可读),事件多路分发器通知 Reactor;
-
Reactor 根据事件类型调用对应处理器的处理方法(如
handleRead()); -
处理器完成业务逻辑(如读取数据、解析协议)。
3. 关键特性
-
同步 I/O 模型:I/O 操作(如
read()/write())由应用程序主动发起,Reactor 仅负责 “通知事件就绪”,不参与实际 I/O。 -
优势:实现简单,无操作系统异步 I/O 依赖,适合 I/O 密集型场景(如高并发网络服务器)。
-
劣势:若处理器处理耗时任务(如复杂计算),会阻塞事件循环,导致其他事件延迟处理。
4. C++ 应用示例
-
知名网络库
muduo(陈硕实现)基于 Reactor 模式,用epoll作为事件多路分发器,配合线程池处理耗时任务。 -
代码框架示意:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29// 事件处理器接口
class EventHandler {
public:
virtual void handleRead() = 0;
virtual void handleWrite() = 0;
virtual int getFd() = 0; // 获取事件源fd
};
// Reactor核心
class Reactor {
public:
void registerHandler(EventHandler* handler, int events); // 注册事件
void removeHandler(EventHandler* handler); // 注销事件
void loop() { // 事件循环
while (true) {
// 调用epoll_wait等待事件就绪
int n = epoll_wait(epfd, events, MAX_EVENTS, -1);
for (int i = 0; i < n; ++i) {
EventHandler* handler = (EventHandler*)events[i].data.ptr;
if (events[i].events & EPOLLIN) {
handler->handleRead(); // 分发读事件
}
if (events[i].events & EPOLLOUT) {
handler->handleWrite(); // 分发写事件
}
}
}
}
};
二、Proactor 模式(前摄器模式)
核心思想:基于 “异步 I/O”,由操作系统完成实际 I/O 操作后,通知应用程序处理 I/O 结果。其核心是 “发起异步 I/O→等待完成→处理结果”。
1. 核心组件
-
异步操作处理器(Async Operation Processor):由操作系统提供,负责执行异步 I/O(如读取数据到缓冲区)。
-
完成事件队列(Completion Queue):存储 I/O 操作完成的结果(如数据、错误码)。
-
完成事件多路分发器:监听完成事件队列,通知 Proactor 有 I/O 完成。
-
Proactor:协调异步操作和结果处理,将完成事件分发给处理器。
-
完成处理器(Completion Handler):处理 I/O 完成后的业务逻辑(如解析数据)。
2. 工作流程
-
应用程序发起异步 I/O 请求(如
aio_read),指定缓冲区、回调处理器,并注册到 Proactor; -
操作系统的异步操作处理器执行 I/O(如从 socket 读取数据到缓冲区);
-
I/O 完成后,操作系统将结果放入完成事件队列;
-
Proactor 通过完成事件多路分发器检测到完成事件,调用对应完成处理器;
-
处理器处理 I/O 结果(如解析缓冲区数据)。
3. 关键特性
-
异步 I/O 模型:I/O 操作由操作系统完成,应用程序仅处理结果,避免 I/O 阻塞。
-
优势:适合高并发场景,I/O 效率高(无应用程序轮询或阻塞等待)。
-
劣势:依赖操作系统异步 I/O 支持(如 Windows 的 IOCP、Linux 的
io_uring),实现复杂,移植性差。
4. C++ 应用示例
-
Linux 下可基于
io_uring实现 Proactor,Windows 可基于 IOCP。 -
代码框架示意(简化io_uring用法):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28// 完成处理器
class CompletionHandler {
public:
virtual void handleCompletion(ssize_t res) = 0; // 处理I/O结果
};
// Proactor核心
class Proactor {
public:
// 发起异步读
void asyncRead(int fd, void* buf, size_t len, CompletionHandler* handler) {
// 提交io_uring异步读请求
struct io_uring_sqe* sqe = io_uring_get_sqe(&ring);
io_uring_prep_read(sqe, fd, buf, len, 0);
sqe->user_data = (uint64_t)handler; // 绑定处理器
io_uring_submit(&ring);
}
void loop() { // 事件循环
while (true) {
struct io_uring_cqe* cqe;
io_uring_wait_cqe(&ring, &cqe); // 等待I/O完成
CompletionHandler* handler = (CompletionHandler*)cqe->user_data;
handler->handleCompletion(cqe->res); // 处理结果
io_uring_cqe_seen(&ring, cqe);
}
}
};
并发编程模式
一、半同步 / 半异步模式(Half-Sync/Half-Async)
核心思想:将系统分为 “异步层” 和 “同步层”,异步层处理 I/O 事件,同步层处理业务逻辑,通过队列连接两层,平衡效率与复杂度。
1. 三层结构
-
异步层:采用 Reactor 模式处理 I/O 事件(如接收连接、读写数据),不阻塞,高效响应事件。
-
同步层:由线程池组成,同步执行业务逻辑(如协议解析、事务处理),避免异步层被耗时任务阻塞。
-
任务队列:异步层将待处理的任务(如 “解析请求”)放入队列,同步层线程从队列取任务执行。
2. 工作流程
-
异步层(Reactor)接收网络事件(如客户端请求),将请求封装为任务;
-
异步层将任务放入任务队列;
-
同步层的线程池从队列中取任务,同步执行业务逻辑(如数据库操作);
-
业务处理完成后,结果通过队列返回给异步层,由异步层发送响应。
3. 关键特性
-
分离 I/O 与业务:异步层专注高效 I/O,同步层专注复杂业务,降低耦合。
-
优势:兼顾高并发 I/O 和复杂业务处理,避免单一线程阻塞整个系统。
-
劣势:任务队列可能成为瓶颈(需考虑线程安全和队列长度);线程池管理增加复杂度。
4. C++ 应用示例
-
多数商业服务器框架采用此模式,如 Nginx(异步层处理连接,同步进程处理请求)。
-
代码框架示意:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28// 异步层(Reactor)
class AsyncLayer {
public:
void onRequest(Request* req) {
taskQueue.push(req); // 请求放入队列
cond.notify_one(); // 唤醒同步层线程
}
};
// 同步层(线程池)
class SyncLayer {
public:
SyncLayer() {
for (int i = 0; i < 4; ++i) { // 4个工作线程
threads.emplace_back([this]() {
while (true) {
std::unique_lock<std::mutex> lock(mtx);
cond.wait(lock, []{ return !taskQueue.empty(); });
Request* req = taskQueue.front();
taskQueue.pop();
lock.unlock();
processRequest(req); // 同步处理业务
}
});
}
}
};
二、领导 / 追随者模式(Leader/Follower)
核心思想:线程池中的线程轮流担任 “领导者”,领导者负责等待事件;事件到来后,领导者指定一个 “追随者” 成为新领导者,自己转为 “处理者” 处理事件;处理完成后回归追随者队列。
1. 核心组件
-
线程池:包含多个相同角色的线程(领导者 / 追随者 / 处理者)。
-
事件多路分发器:仅由当前领导者持有,用于等待事件。
-
事件队列:暂存待处理事件(可选,用于批量处理)。
-
线程屏障(Barrier):协调线程角色切换(如领导者选举)。
2. 工作流程
-
初始时,一个线程成为领导者,其他为追随者;
-
领导者通过事件多路分发器等待事件;
-
事件到来后,领导者从追随者中选一个线程作为新领导者(接管事件多路分发器);
-
原领导者转为处理者,处理当前事件;
-
处理完成后,处理者变回追随者,等待下次选举。
3. 关键特性
-
无锁设计:线程角色切换通过屏障协调,避免锁竞争,减少开销。
-
优势:适合短任务处理(如事件分发),线程切换效率高,适合高并发场景。
-
劣势:不适合长任务(会阻塞领导者选举,导致事件处理延迟);实现复杂(需精细控制线程状态)。
4. C++ 应用示例
-
常用于高性能事件驱动框架(如 ACE 库的
ACE_Leader_Follower)。 -
核心逻辑示意:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21class LeaderFollower {
public:
void run() {
while (true) {
if (isLeader()) {
// 领导者等待事件
Event* event = eventDemux.wait();
// 选新领导者
Thread* newLeader = selectFollower();
newLeader->becomeLeader();
// 处理事件
processEvent(event);
// 变回追随者
becomeFollower();
} else {
// 追随者等待成为领导者
barrier.wait();
}
}
}
};
总结与对比
| 模式 | 核心机制 | 适用场景 | 典型依赖 / 库 |
|---|---|---|---|
| Reactor | 同步事件驱动(等事件→处理) | 高并发 I/O、短任务 | epoll、muduo |
| Proactor | 异步 I/O(OS 完成 I/O→通知) | 超大规模并发、异步 I/O 支持 | IOCP、io_uring |
| 半同步 / 半异步 | 异步 I/O + 同步业务 + 任务队列 | 复杂业务 + 高并发 I/O | 线程池 + Reactor |
| 领导 / 追随者 | 线程轮流领导 + 无锁处理 | 高并发短任务、事件分发 | ACE 库、自定义线程池 |
在 C++ 网络编程中,Reactor 模式因实现简单且兼容性好,是最常用的基础模式;Proactor 适合对性能要求极高且依赖特定 OS 的场景;半同步 / 半异步是架构级设计,平衡了效率与业务复杂度;领导 / 追随者则适合追求极致性能的短任务处理场景