一文带你深入了解Linux五种I/O模型和I/O多路复用



这个思维导图主要涵盖了 Linux 五种 I/O 模型I/O 多路复用(select/poll/epoll) 的核心知识点。我将按照你的结构分模块详细解答,并总结常见的面试题。


一、几种典型 I/O 模型

1. 阻塞 I/O

定义:进程发起 I/O 系统调用后,内核等待数据准备完成,进程被挂起(阻塞),直到数据从内核复制到用户空间,调用才返回。
特点

  • 调用是否立即返回:
  • 功能是否由自己完成:(同步)。
  • 例子:read()write() 默认行为。

2. 非阻塞 I/O

定义:进程发起 I/O 调用后,如果内核数据未准备好,立即返回一个错误码(如 EWOULDBLOCK),进程可以继续轮询检查。
特点

  • 调用是否立即返回:
  • 功能是否由自己完成:(同步)。
  • 需要循环调用,浪费 CPU。

3. 信号驱动 I/O

定义:进程发起调用后立即返回,当数据准备好时,内核发送 SIGIO 信号通知进程,进程再通过 recvfrom 等调用读取数据。
特点

  • 调用是否立即返回:
  • 功能是否由自己完成:(异步通知,但读取仍需自己完成,严格说是“异步通知型同步 I/O”)。
  • 适用于 UDP,TCP 较复杂。

4. I/O 多路复用(高级 I/O)

定义:通过 select/poll/epoll 监控多个文件描述符,当某个描述符就绪时,通知进程进行 I/O 操作。
特点

  • 阻塞在 select 上,而非单个 I/O。
  • 可以同时监控多个 fd。

5. 异步 I/O(AIO)

定义:进程发起 aio_read 等调用后立即返回,内核完成数据准备并复制到用户空间后,通过信号或回调通知进程。
特点

  • 调用是否立即返回:
  • 功能是否由自己完成:(内核完成全部操作)。
  • 真正的异步 I/O。

二、阻塞与非阻塞 vs 同步与异步

维度 阻塞与非阻塞 同步与异步
关注点 调用是否立即返回 I/O 操作由谁完成
组合 阻塞 I/O、非阻塞 I/O 同步 I/O、异步 I/O
  • 阻塞 I/O:调用不返回,直到数据就绪。
  • 非阻塞 I/O:调用立即返回,数据未就绪则返回错误。
  • 同步 I/O:进程自己负责将数据从内核复制到用户空间。
  • 异步 I/O:内核负责全部,完成后通知进程。

三、I/O 多路转接模型

1. select

实现流程

  1. 调用 select,传入 fd_set 集合。
  2. 内核遍历所有 fd,检查状态。
  3. 有 fd 就绪或超时,返回。
  4. 用户遍历 fd_set 找到就绪 fd。

优点

  • 跨平台支持好。

缺点

  • fd 数量受限(FD_SETSIZE,通常 1024)。
  • 每次调用都要将 fd_set 从用户态拷贝到内核态。
  • 返回后需要遍历所有 fd 才能知道哪些就绪。

2. poll

实现流程

  1. 调用 poll,传入 pollfd 数组。
  2. 内核遍历 pollfd,检查事件。
  3. 有 fd 就绪或超时,返回。
  4. 用户遍历 pollfd 检查 revents。

优点

  • 无最大 fd 数限制(基于链表)。
  • 传入传出分离(events 和 revents)。

缺点

  • 仍然需要遍历所有 fd。
  • 大量 fd 时性能线性下降。

3. epoll

实现流程

  1. epoll_create 创建 epoll 对象。
  2. epoll_ctl 注册要监控的 fd。
  3. epoll_wait 等待事件发生。
  4. 返回就绪事件列表。

触发方式

  • 水平触发(LT):只要 fd 可读/写,每次 epoll_wait 都会返回。
  • 边缘触发(ET):仅在状态变化时通知一次,需要非阻塞 fd + 循环读写。

优点

  • 仅返回就绪 fd,无需遍历。
  • 使用红黑树管理 fd,增删改查高效。
  • 支持边缘触发,提高效率。

缺点

  • 仅 Linux 支持。
  • 边缘触发编程复杂。

惊群问题

定义:多个进程/线程同时 epoll_wait 同一个 fd,当事件发生时,所有进程都被唤醒,但只有一个能处理,造成资源浪费。
解决

  • Linux 内核 4.5+ 解决了 epoll 惊群(EPOLLEXCLUSIVE)。
  • 也可用 SO_REUSEPORT 或自己实现负载均衡。

四、常见面试题总结

1. 阻塞与非阻塞的区别?

  • 阻塞:调用不返回直到完成。
  • 非阻塞:调用立即返回,未完成则返回错误。

2. 同步与异步的区别?

  • 同步:进程自己完成 I/O(包括等待和复制)。
  • 异步:内核完成 I/O,完成后通知进程。

3. select、poll、epoll 的区别?

  • select:fd 有限、每次全量拷贝、返回后需遍历。
  • poll:无上限、仍遍历、传入传出分离。
  • epoll:事件驱动、只返回就绪 fd、高效、支持 ET。

4. epoll 的 LT 和 ET 区别?

  • LT:安全、简单,但可能重复通知。
  • ET:高效、需配合非阻塞 I/O 循环读写。

5. 什么是惊群问题?如何解决?

  • 多个进程等待同一事件,事件触发时全部唤醒。
  • 使用 EPOLLEXCLUSIVE 或 SO_REUSEPORT。

6. 什么时候用 select/poll/epoll?

  • select:简单、跨平台、少量 fd。
  • poll:fd 数量较多但变化不大。
  • epoll:高性能服务器、大量并发连接。

如果你需要我画一个流程图对比表格,或者整理成 PDF 笔记,也可以告诉我。

总结

这篇文章是作者搜集大量面经和资料这里出来的。感谢你的支持
作者wkm是一名中国矿业大学(北京) 大一的新生,希望得到你的关注
如果可以的话,记得一键三联!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐