{"name":"IO模型","id":"计算机网络-IO模型","content":"# I/O 模型\n\n## 1. 概述（Overview）\n\nI/O 模型是操作系统、网络协议栈与上层应用在数据交互过程中所遵循的“协作方式”。\n它决定了：\n\n* 程序如何等待数据？\n* CPU 与内核如何调度资源？\n* 多连接如何并行？\n* 高并发系统如何避免线程爆炸与内存浪费？\n\n从业务层看，I/O 模型影响系统吞吐、延迟、并发上限。\n从工程层看，I/O 模型决定框架选择、架构模式（Reactor/Proactor）及优化路径。\n从本质层看，I/O 模型是**如何协调 CPU（计算资源）、线程（执行单元）、内核（数据源）之间的等待关系**。\n\n---\n\n## 2. 本质（Essence）\n\nI/O 模型不是“如何读写数据”，而是：\n\n### **CPU 是主动等待还是被动唤醒？**\n\n不同 I/O 模型的本质区别是：\n**等待阶段由谁承担？**\n\n* 同步阻塞：线程自己等\n* 同步非阻塞：线程轮询\n* I/O 多路复用：线程等待 OS 通知\n* 信号驱动：OS 信号通知\n* 异步 I/O：内核完成全部操作并回调通知\n\n最终目标：\n**减少线程浪费，提升 CPU 利用率，让等待更智能。**\n\n---\n\n## 3. I/O 模型全景图（Panorama）\n\n```\n┌──────────────────────────────────────────────┐\n│                应用层（APP）                  │\n└──────────────────────────────────────────────┘\n               ▲              ▲\n               │ 回调/事件    │\n               │              │\n┌──────────────────────────────────────────────┐\n│           内核态（Kernel Space）              │\n│   网络协议栈 | 驱动 | 中断 | I/O 队列          │\n└──────────────────────────────────────────────┘\n\n                 I/O 模型差异 = 谁负责等待？\n```\n\n---\n\n## 4. 模型（Models）\n\n```bash\n                     ┌───────────────┐\n                     │ CPU / 应用线程 │\n                     └───────────────┘\n                             │\n                   ┌─────────▼─────────┐\n                   │   IO 抽象模型层    │\n                   │ BIO / NIO / AIO   │\n                   └─────────┬─────────┘\n           ┌──────────────────┼──────────────────┐\n           │                  │                  │\n    ┌──────▼─────┐    ┌──────▼─────┐    ┌──────▼─────┐\n    │ 同步模型   │    │ 多路复用   │    │ 异步模型   │\n    └───────────┘    └───────────┘    └───────────┘\n             （底层对应 select/poll/epoll）\n```\n\n### **模型 1：阻塞 I/O（Blocking I/O）**\n\n* 调用 recv() 后线程一直阻塞直到数据准备好\n* 简单但低效\n* 适用于小规模连接、简单场景\n\n**优点：** 编程简单\n**缺点：** 线程占用 = 连接数，无法扩展\n\n---\n\n### **模型 2：非阻塞 I/O（Non-blocking I/O）**\n\n* recv() 立即返回，不等待\n* 程序不断轮询尝试 read\n* 高 CPU 消耗\n\n**优点：** 不阻塞线程\n**缺点：** 空轮询浪费 CPU，实用性差\n\n---\n\n### **模型 3：I/O 多路复用（poll / select / epoll）**\n\n* 本质：**让 OS 帮你阻塞等待多个连接**\n* 应用只在“事件就绪后”才读写\n* 现代高并发框架的基础（NIO、Netty、Node.js）\n\n**优点：** 高效、高并发、线程少\n**缺点：** 存在事件回调开销与内核复杂性\n\n**主要实现方式**\n\n| 方法         | 核心机制                           | 特点                 | 局限性                               |\n| ---------- | ------------------------------ | ------------------ | --------------------------------- |\n| **select** | 用户空间传入 fd 集合，内核轮询并返回就绪集合       | 简单，跨平台好            | 文件描述符数量有限（通常 1024），每次调用都需拷贝 fd 集合 |\n| **poll**   | 以结构数组形式传递 fd 集合，支持大于 1024 个描述符 | 支持更多 fd            | 每次调用仍需内核-用户空间拷贝，性能随 fd 数量增长下降     |\n| **epoll**  | 内核维护 fd 与事件映射表，用户态与内核态共享内存     | 高效，支持成千上万 fd，无重复拷贝 | Linux 专用，复杂度稍高                    |\n\n#### **select/poll 原理**\n\n1. **用户空间构造 fd 集合**\n\n   * 将所有需要监听的文件描述符填入集合或数组\n2. **系统调用进入内核**\n\n   * 内核遍历 fd 集合，检查每个 fd 是否就绪（read/write/error）\n3. **内核返回结果**\n\n   * 将就绪的 fd 列表返回用户空间\n4. **应用遍历就绪 fd**\n\n   * 根据不同事件类型执行对应的读写操作\n\n**性能问题**：\n\n* 每次调用都要**复制 fd 集合**（用户态 ↔ 内核态）\n* 当 fd 数量非常大时，遍历开销显著\n* **轮询行为导致 CPU 消耗大**\n\n```c\nint select(int __nfds, fd_set *__readfds, fd_set *__writefds, fd_set *__exceptfds, struct timeval *__timeout);\n\nint poll(struct pollfd *__fds, nfds_t __nfds, int __timeout);\n```\n\n---\n\n#### **epoll 原理与优化**\n\n**核心思想**：由内核维护事件集合，应用只需“注册 fd 与事件”，就绪事件通过共享内存返回，无需每次遍历所有 fd。\n\n1. **epoll_create / epoll_create1**\n\n   * 创建 epoll 实例，内核分配事件表\n2. **epoll_ctl**\n\n   * 添加、修改或删除 fd 与感兴趣事件\n3. **epoll_wait**\n\n   * 阻塞等待事件就绪，仅返回就绪 fd 列表\n   * 未就绪 fd 不返回，避免无效遍历\n\n**性能优势**：\n\n* **共享内存**：fd 与事件映射表位于用户态 + 内核态共享空间\n* **O(1) 查询**：只返回有事件的 fd，而非全部轮询\n* **高并发能力**：轻松处理上万甚至百万级 fd\n\n```c\nint epoll_create(int size);\nint epoll_create1(int flags);\n\nint epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);\n\nint epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);\n```\n\n```mermaid\ngraph TB\nA[应用程序] --调用--> B(epoll_wait)\nB --返回就绪事件--> C[事件循环]\nC --遍历就绪事件--> D{事件类型}\nD --新连接事件--> E[建立新连接]\nD --读事件--> F[读取数据]\nD --写事件--> G[发送数据]\nD --关闭事件--> H[关闭连接]\n```\n\n### **模型 4：信号驱动 I/O（Signal-Driven I/O）**\n\n* 内核用 SIGIO 通知应用准备好\n* 较少使用，复杂，可用性差\n\n**优点：** 线程不阻塞\n**缺点：** 信号难用、不可靠、跨平台差\n\n---\n\n### **模型 5：异步 I/O（AIO / IO_uring）**\n\n* **最高级模型**\n* 内核不仅通知“准备好”，还完成读写后通知\n* 应用只处理完成事件\n\n**优点：** 真正的异步、高吞吐、低延迟\n**缺点：** 实现复杂、平台差异大；IO_uring 才真正好用\n\n---\n\n## 5. 能力边界（Capability Boundary）\n\n| 模型   | 内核/应用负责内容 | 优势    | 适用场景              |\n| ---- | --------- | ----- | ----------------- |\n| 阻塞   | 应用等待 + 读写 | 简单    | 小业务、脚本            |\n| 非阻塞  | 应用轮询      | 简单但低效 | 少                 |\n| 多路复用 | 内核等待、应用读写 | 并发强   | Web / IM / API 网关 |\n| 信号驱动 | 内核信号通知    | 中等    | 少                 |\n| AIO  | 内核完成全部流程  | 最强    | 高性能、IO 密集         |\n\n关键区别：\n**I/O 多路复用是事件驱动模型的基础；AIO 是最终形态。**\n\n---\n\n## 6. 架构模式关联（Architectural Patterns）\n\n### **Reactor 模式（基于多路复用）**\n\n映射到：\n\n* Java NIO\n* Netty\n* libevent\n* Node.js (libuv)\n\n核心流程：\n\n```\n事件就绪 → Select 返回 → 应用层发起 read/write\n```\n\n本质：**事件通知 + 应用负责 I/O**\n\n---\n\n### **Proactor 模式（基于 AIO）**\n\n映射到：\n\n* Linux io_uring（未来标准）\n* Windows IOCP\n\n核心流程：\n\n```\n应用提交IO → 内核执行IO → 回调通知完成\n```\n\n本质：**内核负责全部 I/O 操作，回调通知应用处理结果**\n\n未来趋势：Proactor + io_uring 将成为主流。\n\n---\n\n## 7. 性能设计原则（Performance Principles）\n\n1. **不要让线程等待 I/O**（浪费）\n2. **不要让线程轮询**（更浪费）\n3. **应该让 OS 代理等待**（select/epoll）\n4. **最终应该让 OS 完成整个 I/O**（io_uring）\n\n---\n\n## 8. 工程实践 / 落地指南（Engineering Implementation）\n\n### **选择 I/O 模型的最佳实践**\n\n| 场景             | 推荐模型           |\n| -------------- | -------------- |\n| 低并发脚本、CLI 工具   | Blocking I/O   |\n| 普通业务系统（<5w连接）  | NIO / epoll    |\n| 高并发高吞吐（>10w连接） | Netty + epoll  |\n| 超高性能定制服务器      | io_uring (AIO) |\n| Windows 服务     | IOCP           |\n\n---\n\n## 9. 与编程语言的关系（Language Mapping）\n\n| 语言      | I/O 模型           | 框架                |\n| ------- | ---------------- | ----------------- |\n| Java    | NIO (epoll)      | Netty             |\n| Go      | epoll + M:N 调度   | Go Runtime        |\n| Node.js | libuv → epoll    | Node              |\n| Rust    | tokio → epoll    | 高性能服务             |\n| C++     | epoll / io_uring | Muduo, Boost.Asio |\n\n趋势：\n**未来框架将逐步从 Reactor（epoll）向 Proactor（io_uring）演进。**\n\n---\n\n## 10. 未来趋势（Future）\n\n### **核心趋势：全面进入 “异步 I/O + 调度器” 时代**\n\n* Linux io_uring = AIO 的真正落地\n* 用户态 I/O（DPDK、SPDK）继续增长\n* 编程语言将和 I/O 结合成统一的 Runtime（如 Go / Rust tokio）\n* Reactor 框架逐步减少，Proactor 成为主流\n\n最终形态：\n\n**“语言 Runtime + 异步内核 + 零拷贝通道” → 极致 I/O 并发**\n\n---\n\n## **总结（Summary）**\n\nI/O 模型体系本质包含三点：\n\n1. **等待责任转移：从线程 → 内核**\n2. **事件驱动与回调是并发的核心抽象**\n3. **AIO 代表未来方向**\n\n## 关联内容（自动生成）\n\n- [/操作系统/输入输出.md](/操作系统/输入输出.md) 详细介绍了操作系统层面对 I/O 的管理机制，包括程序控制 I/O、中断驱动 I/O、DMA 等，与 I/O 模型的底层实现密切相关\n- [/操作系统/linux/内核.md](/操作系统/linux/内核.md) 包含了 Linux 内核对网络系统的管理，特别是 NAPI 和网络包处理机制，与 I/O 多路复用模型在内核层面的实现相关\n- [/计算机网络/网络编程.md](/计算机网络/网络编程.md) 探讨了网络编程中的并发模型与 I/O 模式，直接关联到 I/O 模型在实际网络编程中的应用\n- [/操作系统/linux/Linux性能优化.md](/操作系统/linux/Linux性能优化.md) 涵盖了网络性能优化的内容，包括网络包的接收与发送流程，与 I/O 模型的性能优化密切相关\n- [/计算机网络/链路层.md](/计算机网络/链路层.md) 介绍了链路层协议如以太网的二进制指数回退算法，与 I/O 模型中的异步处理思想相关\n- [/操作系统/进程与线程.md](/操作系统/进程与线程.md) 讨论了进程同步问题，与 I/O 模型中同步与异步的概念相关\n- [/软件工程/架构/系统设计/高并发.md](/软件工程/架构/系统设计/高并发.md) 涉及高并发系统设计，I/O 模型是实现高并发系统的关键技术基础\n","metadata":"tags: ['并发编程', '网络', '消息队列']","hasMoreCommit":false,"totalCommits":2,"commitList":[{"date":"2026-02-12T14:07:03+08:00","author":"MY","message":"doc: 整理标签","hash":"290b3e8ad18f48832ac282290238d020fc030a88"},{"date":"2025-11-27T16:02:19+08:00","author":"MY","message":"docs(computer-network): 添加 IO 模型文档并更新目录结构","hash":"d749abf0730a399acd647c4d03ccc96890484687"}],"createTime":"2025-11-27T16:02:19+08:00"}