阻塞&非阻塞 和 同步&异步
2025-01-22 08:19:30    968 字   
This post is also available in English and alternative languages.

阻塞、非阻塞、同步、异步的概念。

需要明确的一点:讨论这些概念时需要注意上下文,或者说要注意场景

网上关于阻塞、非阻塞、同步、异步概念的讨论很多,OP结合学习到的内容,梳理下自己的观点。


1. 进程通信层面

《操作系统概念:Java实现 - 第七版》中是如下描述的:

进程间的通信可以通过调用send()receive()两种基本操作完成的,具体如何实现这两种基础操作,存在着不同的设计。

消息传递可以是阻塞(blocking)非阻塞(nonblocking),也称为同步(synchronous)异步(asynchronous)

  • 阻塞发送:发送进程阻塞,直到消息被接收进程或邮箱所接收。
  • 非阻塞发送:发送进程发送消息并继续操作。
  • 阻塞接收:接收者阻塞,直到有消息可用。
  • 非阻塞接收:接收者收到一个有效消息或空消息。

上述不同类型的发送方式和不同类型的接收方式,可以自由组合。

在进程通信层面讨论时, 阻塞&同步非阻塞&异步 就是一对同义词, 且需要针对 发送方接收方 作区分对待


2. I/O系统调用层面

知识准备:《UNIX网络编程卷1 - chapter6.2(I/O模型)》、Linux 网络IO模型,了解五种网络IO模型。

五种网络IO模型中,blocking I/O(阻塞式I/O)、nonblocking I/O(非阻塞I/O)、I/O multiplexing(I/O多路复用)、signal driven I/O(信号驱动式I/O) 都是同步的;只有 asynchronous I/O(异步I/O)是异步的。

获取数据(一个I/O)的过程分为两步:

  1. 请求(request) :由 调用方 发起
  2. 响应(response):由 被调用方 返回。

  • 阻塞 & 非阻塞

    阻塞 & 非阻塞 的区别在于第一步,调用方 请求(request) 的过程中是否需要等待?

    如果 调用方 需要等待才能拿到结果,那就是阻塞。

    如果 调用方 不需要等待就能拿到结果,那就是非阻塞。


  • 同步 & 异步

    同步 & 异步 的区别在于第二步,被调用方的 响应(response) 是否需要 调用方 等待?

    如果 被调用方 的响应需要 调用方等待,那就是同步。

    如果 被调用方 的响应不需要 调用方等待,那就是异步。


  • 再论 同步 & 异步

    blocking I/O(阻塞式I/O)、nonblocking I/O(非阻塞I/O)、I/O multiplexing(I/O多路复用)、signal driven I/O(信号驱动式I/O) 这四种网络I/O模型都是同步,是因为它们在发起真正I/O操作时都会阻塞用户程序,至少会让用户程序等待在「内核数据准备好」和「数据从内核态拷贝到用户态」这两个点中的一个。

    而只有 asynchronous I/O(异步I/O) 不会阻塞用户程序,kernel(内核) 会将数据主动copy到用户态中,然后通知用户程序进行处理。


此处 非阻塞异步 的区别:

非阻塞:立即返回的是任何可以立即拿到的数据,可以是完整的结果,也可以是不完整的结果,还可以是一个空值。

异步:结果必须是完整的, 但是这个操作完成的通知可以延迟到将来的一个时间点。

非阻塞 与 异步 都是非阻塞行为,它们的差异仅仅是返回结果的方式和内容不同。


3. Reference