C++ 高性能网络服务骨架(四)—— 从阻塞模型到 Reactor:服务端并发模型进阶

张开发
2026/4/17 23:39:30 15 分钟阅读

分享文章

C++ 高性能网络服务骨架(四)—— 从阻塞模型到 Reactor:服务端并发模型进阶
这一篇要解决什么前面你已经有了✔ 阻塞版 TCP 服务端能跑✔ 线程池接入能并发✔ 服务骨架有结构但还有一个根本问题❌一个连接 ≈ 一个线程线程会被阻塞这一篇要回答如何用“更少线程”处理“更多连接”一、先复盘你走过的三种模型1️⃣ 单线程阻塞第一篇accept → read → write → close 问题串行处理 ❌一个慢请求拖死全局 ❌2️⃣ 线程池 阻塞 IO第二篇主线程 accept ↓ 线程池 read → write 优点能并发 ✔ 问题一个连接 → 占一个线程 ❌3️⃣ 服务骨架第三篇read → parse → dispatch → encode → write 优点有结构 ✔可扩展 ✔ 问题❌ 底层 IO 还是阻塞的二、真正的瓶颈在哪核心问题不是线程池而是线程被阻塞了举个真实场景10000 个客户端连接如果每个连接read() 阻塞 你需要10000 个线程 ❌直接崩三、关键转折点非阻塞 IO阻塞 IOread(fd, ...) 没数据❌ 卡住线程非阻塞 IOfcntl(fd, F_SETFL, O_NONBLOCK); 没数据✔ 立刻返回不会卡住四、但新问题来了如果不阻塞read(fd) 没数据 → 返回 你就得疯狂轮询while循环 ❌ CPU 会炸五、这就引出 epollepoll 做什么告诉你哪些 fd “可以读 / 可以写”核心思想你不用问“有没有数据”↓内核主动告诉你“有数据了”六、epoll 模型核心图┌────────────┐ │ epoll │ └────────────┘ │ ┌────────────┼────────────┐ ▼ ▼ ▼ fd1就绪 fd2就绪 fd3就绪 │ │ │ ▼ ▼ ▼ read read read七、核心 API你先有个印象epoll_create() epoll_ctl() epoll_wait()最关键的是epoll_wait(...) 返回所有“就绪的 fd 列表”八、从线程池模型 → epoll 模型线程池模型一个连接 → 一个线程epoll 模型一个线程 → 管理多个连接 本质变化线程不再绑定连接而是绑定“事件”九、Reactor 模型核心思想你会听到一个词ReactorReactor 是什么事件驱动的处理模型模型图epoll_wait()│▼有事件发生fd ready│▼分发给 handler│▼处理 read / write对应你现在的代码fd ready↓ConnectionHandler↓parse / dispatch / encode 你第三篇的结构已经是 Reactor 的“处理层” 十、把你现在的认知彻底打通你现在有三层第一层IO模型模型特点阻塞 IO卡线程非阻塞 IO不卡线程epoll事件驱动第二层执行模型模型特点单线程串行线程池多线程Reactor少线程多连接第三层服务骨架ConnectionHandler↓Parser↓Dispatcher↓Encoder 十一、最关键的跃迁必须理解之前线程 连接之后线程 事件循环连接 状态机 这句话非常重要。 十二、为什么 Nginx 能扛高并发因为一个线程↓epoll↓管理几万连接 而不是一个连接一个线程 ❌ 十三、这一篇真正的价值不是让你会写 epoll而是你开始理解并发的本质不是线程多而是“调度方式”不同 十四、你现在的完整认知图线程池执行引擎↓阻塞 IO简单模型↓服务骨架处理链↓非阻塞 IO不阻塞线程↓epoll事件通知↓Reactor统一调度模型 十五、你现在达到了什么水平你已经✔ 理解 socket✔ 理解 fd✔ 理解线程池✔ 理解服务骨架✔ 理解阻塞 vs 非阻塞✔ 理解 epoll 作用✔ 理解 Reactor 思想 这已经是服务端并发架构入门到进阶的完整闭环 最后一段最重要你现在要记住一句话线程池解决“怎么执行”epoll/Reactor 解决“什么时候执行” 前三篇解决怎么处理请求 第四篇解决什么时候处理请求事件驱动

更多文章