理解 I/O 先拆成两个阶段:等待数据就绪,以及把数据从内核缓冲区交给用户缓冲区。阻塞/非阻塞主要描述调用在等待阶段是否让调用线程停住;同步/异步描述应用是否要亲自推进数据操作、何时得到“操作完成”的结果。两组词回答不同问题,不能把非阻塞直接等同异步。
阻塞 I/O:数据未就绪时 read 等待;数据到达后,通常还要完成拷贝才返回。非阻塞 I/O:数据未就绪时立刻返回暂不可用,应用可做别的事,但需再次尝试或等待通知;不断空轮询会浪费 CPU。I/O 多路复用(select/poll/epoll)等待多个描述符的就绪状态,收到可读通知后应用仍调用 read 取数据,因此通常属于同步 I/O 的就绪通知模式。
异步 I/O则是应用提交读写请求后继续执行,由内核或运行时推进操作,在完成后通知应用并提供结果。真正异步语义依具体 API、文件系统、设备与运行时实现;线程池包装也能让调用方不阻塞,但底层可能仍是工作线程阻塞等待。信号驱动 I/O 常在状态变化时通知就绪,随后仍由应用执行读写,也不能仅因“异步通知”就认定数据拷贝已完成。
网络面试中还要注意:就绪只表示现在可以尝试读写,不保证一条应用消息已完整到齐;TCP 是字节流,read 可能只返回部分数据。异步提交后则需遵守缓冲区生命周期、取消与错误处理规则。架构选择要看并发量、连接活跃度、内存和状态管理成本,而不是只比较名词。
常见追问
Q:非阻塞 I/O 是异步 I/O 吗?
A:不是。非阻塞未就绪时及时返回,后续仍由应用再次读写;异步 I/O 通常由系统/运行时完成已提交操作,再给出完成通知。
Q:epoll 报告可读后,数据已经复制到用户态了吗?
A:没有。它报告就绪,应用仍要调用 read/recv,读取过程才把数据交给用户缓冲区。
Q:阻塞/非阻塞与同步/异步是同一条分类轴吗?
A:不是。前者描述调用等待时线程的行为,后者描述 I/O 完成与应用责任;非阻塞轮询仍可属于同步 I/O。
Q:异步调用返回成功意味着读完了吗?
A:通常只表示请求已成功提交;要等完成事件并检查实际字节数、错误状态,才能判断操作结果。