摘要:开发过程中经常遇到程序莫名卡住、服务响应缓慢,CPU 占用率却并不高,很多时候根源并不是死循环或者代码 Bug,而是IO 阻塞。本文通俗讲解 IO 阻塞原理、文件读取底层流程,区分 IO 等待与 CPU 高负载,梳理典型现象、排查手段与优化方案,帮助开发者理解文件读写、网络请求、数据库访问、并发服务中的等待瓶颈。
写代码的时候你大概率遇见过这样的现象:明明只写了一行读取文件的代码,程序却像暂停卡住;后端服务 CPU 空闲,但接口响应迟迟不返回;桌面软件读取大文件直接显示 “未响应”。很多人第一反应怀疑死循环、程序崩溃,实际很多场景是发生了 IO 阻塞。IO 阻塞是理解并发编程、服务性能调优的基础概念。
一、什么是 IO?
IO,全称 Input/Output,输入输出。对于程序而言,下面这些操作全部属于 IO:
本地文件读写、配置文件加载
网络接口调用、接收发送网络数据
数据库查询、缓存读写
键盘、外设输入输出
IO 的共同特征:数据不在 CPU 内部,保存在磁盘、网卡、远程服务器、内核缓冲区等外部载体。
CPU 和内存运算速度极快,但硬盘、网络、远程数据库速度慢上好几个数量级。当程序需要外部的数据,CPU 只能等待外部设备把数据准备完成,这一段等待时间,就是 IO 阻塞发生的根源。
二、IO 阻塞到底是什么?
IO 阻塞:程序发起 IO 调用之后,在数据返回之前,当前线程被挂起,无法继续向下执行后续逻辑。
举个通俗比喻:程序执行计算,就像坐在办公桌做算术题,自己立刻就可以完成;IO 操作相当于到档案室调取档案,提交申请之后,你只能原地等待工作人员查找资料,这就是阻塞等待。线程不会占用 CPU 疯狂运算,而是进入休眠等待状态,操作系统把 CPU 资源调度给其他线程使用。直到数据准备完毕,再唤醒线程继续运行。
重点误区:IO 阻塞 ≠ CPU 繁忙。程序卡住无响应,CPU 占用很低,极有可能就是 IO 阻塞;CPU 占满一般来自循环、大量计算任务。阻塞的本质不是算不过来,而是外部资源数据还没准备好。