select 是最古老的 I/O 多路复用 机制。它允许进程同时监控多个 文件描述符 (FD) 的就绪状态。
核心逻辑
select 的核心是使用 位图 (Bitmap) 来管理 FD 集合。
- 位图映射:用一个固定长度的位图(通常 1024 位)表示监控的 FD。第 位为 1 表示监控 FD 。
- 全量拷贝:每次调用都需要将整个位图从用户态拷贝到内核态。
- 原地修改:内核发现就绪 FD 后,会直接修改传入的位图来标记就绪状态。
- 线性触发:内核返回后,用户进程必须 遍历整个位图才能找到具体哪个 FD 就绪。
sequenceDiagram participant U as 用户进程 participant K as 内核 (Kernel) U->>U: 初始化 fd_set (位图) U->>K: select(max_fd, &readset, ...) Note over K: 拷贝位图到内核 Note over K: 线性扫描所有 FD K-->>K: 发现数据就绪 Note over K: 修改位图,仅保留就绪位 K->>U: 返回就绪数量 Note over U: O(N) 遍历位图找出就绪 FD
致命缺陷
- 1024 限制:受限于
FD_SETSIZE,单个进程最多只能监控 1024 个 FD。 - 不可复用:内核会原地修改位图,导致下次调用前必须重新初始化。
- 性能瓶颈:
- 拷贝开销:每次调用都要全量拷贝位图。
- 扫描开销:内核和用户态都需要 遍历,FD 越多越慢。