五种 IO 模型与 select、poll、epoll 对比

这篇笔记以 Unix 网络 I/O 的经典分类为线索,比较等待数据就绪和把数据交付给应用程序这两个阶段。就绪通知与操作完成通知的区别,是理解这些模型的关键。

1. 阻塞 IO 模型

应用调用阻塞式 recv 等接口后,如果数据尚未就绪,调用线程会等待;数据就绪后再把数据复制到用户缓冲区,随后返回。正常完成读取时,应用才获得数据;调用也可能因错误、中断或超时而返回。

典型例子是阻塞 socket。等待期间线程通常被挂起,不需要持续忙轮询;实现相对直观。并发连接较多时,如果为每个连接长期占用一个线程,会增加线程和调度成本,是否适合仍需结合工作负载评估。

2. 非阻塞 IO 模型

设置非阻塞标志后,读取时若暂时没有可读数据,接口通常以 EAGAIN 或 EWOULDBLOCK 返回,应用稍后重试。数据就绪时,读取调用仍需完成实际的数据交付;非阻塞不等于异步完成通知。

应用可以反复尝试读取,但忙轮询会消耗 CPU。实际程序常把非阻塞 socket 与 I/O 多路复用结合起来,避免逐个连接持续轮询。

3. IO 多路复用模型

一个线程可以等待多个文件描述符的就绪事件。select、poll 或 epoll_wait 返回后,应用再对就绪的描述符执行读写。这里监控的是文件描述符;可以属于同一进程内的多个连接,并不要求每个连接对应一个独立进程。

多路复用接口本身可以阻塞等待事件。事件就绪也不代表数据已经复制到用户缓冲区,因此通常会配合非阻塞读写,并处理暂时无数据、部分读写和连接关闭等情况。

select、poll、epoll 的区别

维度 select poll epoll
描述符集合 每次传入并在返回后重建集合 每次传入描述符数组 通过 epoll_ctl 维护兴趣集合,epoll_wait 获取就绪事件
数量限制 Linux 常用 glibc 的 FD_SETSIZE 为1024,限制的是可表示的描述符编号 没有 select 的固定集合限制,仍受进程及系统资源限制 没有 select 的固定集合限制,仍受描述符、内存和监听资源限制
就绪结果处理 需要检查返回的集合 需要检查返回的数组 返回就绪事件,应用按返回结果处理
等待方式 可阻塞或设置超时 可阻塞或设置超时 可阻塞或设置超时,timeout为0时立即返回
通知模式 通常按水平触发理解 通常按水平触发理解 支持水平触发和边沿触发

epoll 的优势来自持续维护监听集合和就绪事件列表,不能概括为"永远不阻塞"或"整个流程都是 O(1)"。返回并处理 k 个事件至少需要与 k 相关的工作量。标准 epoll 接口也不是通过 mmap 把监听列表直接映射给用户空间。

上述行为可参考 Linux select 手册、epoll 手册和 epoll_wait 手册。

4. 信号驱动 IO 模型

应用请求在 I/O 就绪时收到信号,然后继续执行其他工作。就绪信号到来后,应用再读取数据。这里通知的是"可以进行 I/O",还不是"整个 I/O 操作已经完成"。具体通知行为取决于描述符类型和系统接口;信号处理也需要遵守相应的安全限制。

5. 异步 IO 模型

应用提交 I/O 请求后继续执行其他工作,操作完成时再通过事件、回调或其他机制获得结果。与就绪通知相比,完成通知表示请求的数据交付操作已经完成,而非要求应用在收到通知后再发起一次常规读取。

异步 API 的实现方式、支持的文件类型和限制依平台及运行时而异,不能仅凭接口名称判断内部是否占用了工作线程,也不能把所有异步接口都视为同一种内核实现。

图示补充

以下示意图沿用原学习笔记。部分图片带有极客时间水印,保留原有署名;具体接口语义以相应系统手册为准。

原文发布于我的个人博客:IO模型。

相关推荐
玄芯散人1 小时前
【金丹·81】性能分析:你的程序慢在哪
linux·性能优化·perf
天意__1 小时前
Linux部署Qwen轻量模型
linux·服务器·qwen
木卫二号Coding2 小时前
第八十六篇-Strata 部署指南(Ubuntu 22.04 + Tesla V100【单卡】)
linux·运维·人工智能·ubuntu
11路没有终点2 小时前
sed 命令详解:文本编辑流处理实战
linux
码完就睡2 小时前
Linux——线程的创建与同步
linux·运维
Lsetea2 小时前
OpenSSL读取加密私钥报bad decrypt:passin与口令来源排查
linux·https·ssl证书·openssl·私钥
FY@-@2 小时前
Shell 脚本编程:条件判断与循环
linux·运维·前端
Peregrine92 小时前
Linux 基本指令大全
linux·运维·服务器
拂拉氏2 小时前
【知识讲解】 Linux动静态链接认识
linux·动静态链接