目录
1、四种 I/O 模型 CPU 开销对比
① 阻塞 IO(BIO)
② 非阻塞 IO
③ IO 多路复用 select/poll/epoll
④ 异步 IO AIO(libaio/io_uring)
2、开销拆分:一次磁盘 / 网络 I/O 完整 CPU 消耗
3、那占多少 CPU?没有固定百分比,看场景
4、面试高频坑点
简单记忆
核心结论:I/O 一定会占用 CPU,但不同 I/O 模型 CPU 开销天差地别;真正读写硬件数据传输阶段可以不占 CPU,但是 I/O 的发起、收尾、中断处理、数据拷贝都要消耗 CPU。
1、四种 I/O 模型 CPU 开销对比
① 阻塞 IO(BIO)
read ()/write () 系统调用,线程挂起等待硬件完成 IO
- 等待数据阶段:线程阻塞休眠,不消耗 CPU
- 数据拷贝阶段(内核→用户空间):CPU 参与内存拷贝,占用 CPU
- CPU 占用:低,大部分时间线程休眠;但线程资源开销大。
② 非阻塞 IO
while 循环轮询调用 read,没数据立刻返回,用户态不停循环询问内核
- 等待数据阶段:用户态循环轮询,CPU 满负载消耗(空转)
- 数据拷贝阶段:CPU 拷贝内存数据
- CPU 占用:很高,CPU 大部分时间在做无效轮询。
③ IO 多路复用 select/poll/epoll
单个线程管理大量 fd
- select/poll:用户态把 fd 集合拷贝内核,内核遍历扫描全部 fd;有事件返回用户态,用户程序遍历 fd 找就绪事件。
- CPU 开销:中等;fd 数量越大,扫描开销越高。
- epoll:事件回调,不需要遍历全部 fd;就绪事件直接返回。
- 等待阶段:线程阻塞休眠,不耗 CPU;
- 就绪事件处理、数据拷贝消耗 CPU。
- CPU 占用:很低,高并发场景首选。
④ 异步 IO AIO(libaio/io_uring)
完全异步:提交 IO 任务给内核,内核完成后通知程序
- 发起 IO 请求:CPU 少量开销,提交任务给内核
- 硬件 DMA 传输数据:完全不占用 CPU,DMA 控制器接管总线搬运数据
- IO 完成产生中断,CPU 处理中断、回调通知应用程序,少量 CPU 开销
- CPU 占用:最低,硬件 DMA 负责搬运,CPU 只负责提交任务和收尾中断。
⚠️重点:DMA!磁盘、网卡都带有 DMA 控制器,硬件和内核缓冲区之间的数据搬运不需要 CPU 参与;但是「内核缓冲区 ↔ 用户缓冲区」内存拷贝,必须 CPU 完成。
2、开销拆分:一次磁盘 / 网络 I/O 完整 CPU 消耗
- 发起系统调用 read/write:CPU 切换用户态→内核态,上下文切换,消耗少量 CPU
- 硬件执行 IO:DMA 搬运硬件数据到内核缓冲区,CPU 可以去干别的事(0 占用)
- IO 完成,硬件触发中断:CPU 暂停当前任务,执行中断处理程序,少量 CPU 开销
- 内核缓冲区拷贝到用户进程内存:内存拷贝,CPU 占用(这一块是主要 CPU 消耗)
- 系统调用返回:内核态切回用户态,上下文切换
所以:I/O 慢不是因为 CPU 忙,而是硬件速度慢;CPU 大部分时间在等待硬件完成动作。
3、那占多少 CPU?没有固定百分比,看场景
- BIO 单线程读文件:CPU 通常1%‑5%,绝大部分时间在等待磁盘,只有拷贝数据时跑 CPU。
- 非阻塞轮询 while (!read ()):CPU 直接拉满接近100%,全部 CPU 耗在空转轮询。
- epoll 高并发网络服务(如 Nginx):CPU 主要消耗在协议解析、业务逻辑、内存拷贝;单纯等待 IO 事件几乎不耗 CPU。
- io_uring 异步磁盘 IO:CPU 开销最小,适合大规模文件读写。
4、面试高频坑点
❌错误:IO 操作完全不占用 CPU ✅正确:硬件 DMA 传输不占 CPU;系统调用、上下文切换、中断处理、内核用户内存拷贝都要 CPU。
❌错误:阻塞 IO 会占用 CPU 等待磁盘 ✅正确:阻塞时线程被调度出去休眠,CPU 运行其他线程,等待阶段 CPU 开销几乎为 0。
零拷贝技术(mmap、sendfile)的意义:就是减少「内核缓冲区→用户缓冲区」的 CPU 内存拷贝,降低 CPU 占用,提升 IO 性能。
- sendfile:直接内核内部拷贝,跳过用户空间,减少 CPU 拷贝开销。
简单记忆
等待硬件:可以不耗 CPU;系统调用、中断、内存拷贝:一定耗 CPU;轮询模型会疯狂浪费 CPU。