Skip to content

12 · 网络编程 IO 模型 ​

为什么 Node 单线程能抗高并发,而阻塞式服务会卡死?答案在 IO 模型。本篇讲阻塞/非阻塞、IO 多路复用与异步,给前后端一个理解"高性能服务网络底座"的直觉。更深层的操作系统视角见 IO 计算机基础。

速览卡 ​

项内容
一句话定位服务端怎么用有限的线程扛海量连接
核心内容阻塞/非阻塞、select/epoll、Reactor、异步
读完能回答Node 单线程为什么能扛住?高并发服务的底座是什么?
相关板块N02 TCP | N07 WebSocket | C07 性能与容量

一、为什么需要 IO 模型 ​

text
一万个连接 = 一万个"在等数据"的任务
如果每个连接占一个线程 → 线程爆炸
模型的目标:用少量线程管大量连接

二、阻塞 vs 非阻塞 ​

模型行为代价
阻塞数据没到就卡住线程连接多线程不够用
非阻塞没数据立刻返回"还没好"需要反复问,CPU 空转

心智模型:阻塞像点餐后干等,非阻塞像不断去柜台问"好了吗"。前者浪费线程,后者浪费 CPU。


三、IO 多路复用:一次盯一群连接 ​

text
select/poll:把一堆连接交给内核,等有事件再处理(但每次全量扫描)
epoll:内核帮你记住关心的连接,只返回就绪的(Linux 高性能标配)
机制特点
select有连接数上限,每次全量查
poll去掉上限,仍全量查
epoll事件驱动,只通知就绪项

四、Reactor:多路复用的工程封装 ​

text
事件循环(Reactor)收到就绪事件 → 分发给处理器
Node / Netty / Python asyncio 都是这个套路

核心思想:永远不要在一个线程里"干等"某个连接,而是"谁好了处理谁"。这就是事件循环的心智模型。


五、同步 vs 异步:差别在"谁等着" ​

维度同步阻塞异步事件驱动
线程等待是否
高并发能力差好
代码复杂度直观需回调/协程管理
代表传统多线程Node、Netty、asyncio

六、与前端的关系 ​

前端概念对应
事件循环就是 Reactor 的 JS 版
await / Promise把异步写得更像同步
大量并发请求浏览器连接池 + 服务端多路复用

你写 await fetch(...) 时,底层正是"非阻塞 + 事件循环"在为你服务。


七、自检清单 ​

  • [ ] 能说清为什么不能"每连接一线程"
  • [ ] 能区分阻塞/非阻塞、同步/异步
  • [ ] 能解释 epoll 比 select 强在哪
  • [ ] 能画出 Reactor 事件循环的分发流程
  • [ ] 知道 Node / asyncio / Netty 用的都是同一套心智

八、常见误区 ​

误区事实
"异步 = 更快"是更省线程,单请求未必更快
"事件循环会并行执行"单线程内仍是轮流,并行靠多进程/多线程
"高并发只要框架选对"底层是 IO 模型 + 连接管理 + 容量设计

九、动手练习 ​

练习 A:阻塞 vs 非阻塞对比 ​

用 Python 分别写阻塞 socket 与 asyncio 版本,压 100 个并发连接,观察耗时与线程占用。

练习 B:看 Node 事件循环 ​

写一个慢 IO 模拟,观察它在等待时不阻塞其他请求,理解单线程真相。

练习 C:读源码注释 ​

读 asyncio 或 libuv 的 README 关于 event loop 的描述,与 Reactor 图对照。


相关文档 ​

本区 ​

其他域 ​