跳到主内容
快讯直播
AI智模界
AI 词典

阻塞 I/O 与非阻塞 I/O:慢请求为何能卡死进程

一句话定义:阻塞 I/O(blocking I/O)指程序发起一次读写调用后,当前线程只能停在原地等结果回来,才继续往下执行;非阻塞 I/O(non-blocking I/O)指调用立刻返回,有数据就交付,没有就先告诉你「还没好」,由你稍后再问。

打个比方:去银行办事。阻塞就是站在窗口前死等,柜员不办完你哪儿也去不了——你这条队伍彻底停摆。非阻塞是拿号后回座位,隔一会儿去瞄一眼叫号屏,这叫做轮询(polling):你能干别的,但反复跑腿也有成本。更聪明的做法是留手机号,柜台办好了打电话叫你,这就是 I/O 多路复用(I/O multiplexing,如 epoll、kqueue 这类机制):一个「前台」统一盯着所有窗口,谁就绪就通知谁。

慢请求凭什么卡死整个进程。一个请求往往要查数据库、调外部接口、读文件,这些等待动辄几十毫秒到几秒。在阻塞模型里,线程等着的这段时间什么都干不了,只能睡着。要同时服务 1000 个请求,就得开 1000 个线程;线程有栈内存开销,切换也有成本,几千个就接近瓶颈。更致命的是雪崩:某个下游突然变慢,线程一个个被「等」住,线程池被占满,新请求只能排队——服务看着没崩,实际所有线程都在等,这就是「一个慢请求拖垮整个进程」的真实机制。

异步框架省下的是什么。异步框架用非阻塞 I/O 加事件循环(event loop):发起调用后立刻返回,把「结果到了之后做什么」注册成回调或挂起的协程,线程转身去处理别的请求,数据就绪时再由事件循环唤醒。它省下的不是 CPU(等待本来也不耗 CPU),而是「为等待而占用的线程」。所以单个事件循环能撑住成千上万条连接。代价是纪律:在事件循环里写一句同步阻塞调用(比如某次同步数据库查询),整个循环就会被堵死,这是最常见的线上事故。

阻塞 I/O非阻塞 I/O
调用之后线程原地等待立即返回
等待的成本占住一个线程只占一点状态
扩大并发靠堆线程/进程事件循环 + 协程
典型风险线程池耗尽阻塞调用堵死循环

几个容易混淆的邻居:阻塞/非阻塞说的是「调用返回前线程在不在等」;同步/异步说的是「结果由谁取、谁通知」,两组词常被混用。非阻塞也不等于更快:单次请求延迟可能更高(多次轮询、调度开销),它赢在吞吐和并发数。并发(concurrency)也不等于并行(parallelism),事件循环是并发而非并行。

对实际工作的意义:选框架时先确认它的 I/O 库是不是异步的;不要在异步处理函数里塞同步重活,CPU 密集型任务交给线程池;对外部调用一律设超时和并发上限。排查故障时也一样:如果服务没崩、内存正常,但请求大面积超时,先怀疑下游变慢把线程「等」满了,而不是先怀疑 CPU。

AI 生成本文由 AI 基于公开信息自动生成,仅供参考。