Linux 五种 IO 模型 + 非阻塞 IO 的完整梳理
(2025-2026 面试/实战最常考版本)
Linux 下最经典的五种 IO 模型,几乎是所有中高级后端/网络编程面试必问内容。
| 序号 | IO 模型名称 | 阻塞阶段 | 进程在内核等待数据时是否阻塞? | 进程在数据从内核→用户缓冲区时是否阻塞? | 是否同步 IO? | 实际使用代表技术 | 性能排序(延迟) |
|---|---|---|---|---|---|---|---|
| 1 | 阻塞式 IO(Blocking IO) | 等待数据到达 + 拷贝到用户缓冲区 | 是 | 是 | 是 | 几乎所有最原始的 read/write | ★(最慢) |
| 2 | 非阻塞式 IO(Non-blocking IO) | —(轮询) | 否(立即返回) | 是(数据到了才拷贝) | 是 | 设置 O_NONBLOCK + 循环 read | ★★ |
| 3 | IO 多路复用(IO Multiplexing) | 等待任意一个 fd 可读/可写 | 是(在 select/poll/epoll 上阻塞) | 否(内核只通知,拷贝仍由进程发起) | 是 | select / poll / epoll / kqueue | ★★★★ |
| 4 | 信号驱动式 IO(Signal-driven IO) | —(内核数据到达时发信号) | 否 | 是(收到信号后自己去 read,仍会阻塞拷贝) | 是 | sigaction + SIGIO | ★★★(很少用) |
| 5 | 异步 IO(Asynchronous IO) | 整个过程都不阻塞 | 否 | 否(内核完成拷贝后通知) | 否 | aio_read / libaio / io_uring | ★★★★★(最强) |
重点对比图(建议背诵的思维导图版)
是否在等待内核数据时阻塞? 是否在数据从内核→用户缓冲区时阻塞? 阻塞IO 是 是 非阻塞IO 否(轮询) 是 IO多路复用 是(阻塞在select/epoll_wait) 否 信号驱动IO 否(等信号) 是 异步IO 否 否非阻塞 IO(Non-blocking IO)的真实使用状态(非常重要!)
// 最经典的错误写法(很多人这样写然后骂系统垃圾)while(1){intn=read(fd,buf,sizeof(buf));if(n>0)// 读到数据process(buf,n);elseif(n==0)// 连接关闭break;else{// n == -1if(errno==EAGAIN||errno==EWOULDBLOCK);// 没数据,继续轮询elseerror();}}上面这种写法的问题:
- CPU 占用极高(疯狂轮询)
- 延迟不确定(取决于你轮询的频率)
- 不适合大量连接(几千个 fd 就爆炸)
非阻塞 IO 的正确打开方式(2024-2026 主流做法)
非阻塞 IO 几乎从来不单独使用!!! 真正的高性能方案永远是下面这几种组合: 1. 非阻塞 + 忙轮询 → 极低延迟场景(游戏、HFT),几百个连接还能接受 2. 非阻塞 + sleep(小间隔) → 低质量方案(基本淘汰) 3. 非阻塞 + select/poll → 古老方案(几百~一千连接) 4. 非阻塞 + epoll(ET/LT) → 目前最主流方案(单线程轻松10w+连接) 5. 非阻塞 + io_uring → 2023~2026 年最强趋势(零拷贝+内核态调度)五种模型实际项目中使用频率(2025-2026 真实分布)
| 占比 | 模型 | 典型场景 | 代表框架/库 |
|---|---|---|---|
| 7080% | IO多路复用(epoll) | 绝大部分高并发网络服务器 | nginx, redis, netty, libevent, libuv |
| 1020% | 异步 IO(io_uring) | 高性能存储、网络代理、新一代服务器 | redis 7+, nginx with io_uring, SPDK |
| ~5% | 纯阻塞 IO | 简单脚本、命令行工具、低并发业务 | 大量业务代码 |
| ~2% | 非阻塞 + 轮询 | 极致低延迟场景(游戏服务器、HFT) | 自研轮询服务器 |
| 极少 | 信号驱动 IO | 几乎已被淘汰(实现复杂,收益低) | 基本没人用 |
快速记忆口诀(面试可直接说)
问你用什么模型的时候,直接甩这句话: "我们项目主要用 epoll 的 ET 模式 + 非阻塞 IO, 少量高性能存储场景正在迁移到 io_uring 异步 IO。 传统阻塞 IO 只在一些低并发工具类代码中使用。"总结一句话
在现代高并发网络编程里,单纯的「非阻塞 IO」几乎没有生存空间,真正起作用的是「非阻塞 IO + 多路复用」或「非阻塞 IO + 异步 IO(io_uring)」。
需要我针对某个具体模型(比如 epoll ET/LT 区别、io_uring 入门实战、信号驱动的正确用法等)再展开详细讲解吗?