核心解答

非阻塞 I/O (Non-Blocking I/O)异步 I/O (Asynchronous I/O) 的核心区别在于:数据拷贝阶段是由谁完成的,以及调用者是否需要主动轮询/等待。

  • 非阻塞 I/O:调用后立即返回。如果数据未就绪,返回错误码(如 EAGAIN);如果数据已就绪,调用者仍需阻塞地将数据从内核空间拷贝到用户空间。它属于 同步 I/O
  • 异步 I/O:调用后立即返回并继续执行。内核负责等待数据就绪并将数据拷贝到用户空间,完成后通过信号或回调通知调用者。它属于真正的 异步 I/O

解答思路

理解这两个概念的关键在于区分 I/O 操作的两个阶段:

  1. 等待阶段:等待数据准备好(例如等待网络数据包到达)。
  2. 拷贝阶段:将数据从内核缓冲区拷贝到用户进程缓冲区。
I/O 模型等待阶段拷贝阶段归类
阻塞 I/O阻塞阻塞同步 I/O
非阻塞 I/O非阻塞(轮询)阻塞同步 I/O
I/O 多路复用阻塞(在 select/epoll 上)阻塞同步 I/O
异步 I/O非阻塞非阻塞异步 I/O

深度解析与面试技巧

面试技巧:避坑指南
  1. 不要混淆“非阻塞”和“异步”:很多初学者认为 epoll 是异步 I/O,其实 epollI/O 多路复用,属于同步 I/O,因为它在数据返回后仍需进程手动调用 read 拷贝数据。
  2. 区分 Node.js/Go 的“异步”:在应用层(如 Node.js),我们常说异步编程,那是通过事件循环和回调实现的。但在底层内核模型中,它们大多是基于 epoll(同步非阻塞)实现的“伪异步”。
  3. 追问方向:面试官可能会接着问:“既然 AIO 这么好,为什么 Linux 下主流还是用 epoll?”(答案通常涉及 AIO 实现的复杂性、成熟度以及 epoll 在处理大量连接时的性能优势)。