浅谈 IO 多路复用

之前面试准备过这里的八股,但觉得理解不够深,故打算再探深些 五种 IO 模型 阻塞 IO 非阻塞 IO IO 多路复用 信号驱动 IO 异步 IO 阻塞 IO 最简单,最易懂 厨子做菜,做不好服务生也等着,等到菜做好再上菜。 不难看出,效率很低,但是实现简单,对应到计算机世界中,这里用 C 语言的 read() 函数去举例(虽然 C 语言烂的一坨:) 用户态调用 read(fd, buf, count) 软中断切入内核态,内核根据 fd 查文件描述符表,找到对应的内核文件描述符 检查页缓存,是不是存在数据(之前用过,缓存还在) 缓存没有,触发磁盘 IO,等待数据,进程阻塞挂起 DMA 数据 Copy 完成,触发硬件中断,进而内核把页缓存的数据 copy_to_user 到用户空间 buf 上面就是一次完整的阻塞 IO,我们可以看出,在用户态触发 read() 后,后面的逻辑基本上都是交由内核态进程去接管的,但是该用户态进程此时卡死在这里,如果 fd 对应的是网络请求,那一个 fd 就得拉一个进程接管,假设上万个请求,那系统中会有上万个阻塞进程,所以不适合并发规模较大的场景。 非阻塞IO 厨子做菜,服务生不断轮询反问厨子有没有做好。 这一点对应到 CPU 就是进程不断调用 read(),如果数据准备好了,read()出数据,如果数据没有准备好,read()出 fasle,得到 false 的进程就去继续调用 read()。 while true: data = read(fd) // 非阻塞调用 if data == EAGAIN or data == EWOULDBLOCK: // 没有数据,立刻返回错误码 do_other_work() // 去做其他事情 else: process(data) // 一旦有数据就处理 break 也就是说,用户线程需要不断询问内核数据是否准备好,虽然能及时获取到数据,但是在没有获取到数据的时候,不会主动交出 CPU 资源,而一直占用 CPU。 ...

August 11, 2025 · 小石堆