塞非阻塞主要描述的是调用者和被调用者之间的关系,同步异步主要描述的是被调用者和结果之间的关系。同步和异步关注的是消息通信机制,阻塞和非阻塞关注的程序在等待调用结果(消息、返回值)时的状态。
一、阻塞非阻塞与同步异步的区别
同步和异步关注的是消息通信机制,所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到了返回值。换句话说,就是由调用者主动等待这个调用的结果。而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。实际结果由被调用者通过状态、通知来通知调用者。
阻塞和非阻塞关注的程序在等待调用结果(消息、返回值)时的状态。阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
我们需要明确一点,阻塞非阻塞与同步异步是两个不同维度的概念,它们并不是对立的。阻塞非阻塞主要描述的是调用者和被调用者之间的关系,同步异步主要描述的是被调用者和结果之间的关系。我们可以用一个餐厅点餐的例子来类比:
假设你去了一个餐厅,你想点一份牛排。你有两种方式来点餐:
- 方式一:你直接对服务员说你要牛排,然后等待服务员给你牛排。在这个过程中,你不能做其他事情,只能等待牛排。这就是阻塞方式。
- 方式二:你给服务员一个号码牌,然后对服务员说你要牛排,并告诉他把牛排做好后放在号码牌对应的位置。在这个过程中,你可以做其他事情,比如喝水、看书等。当你想吃牛排时,你再去号码牌对应的位置取牛排。这就是非阻塞方式。
从上面可以看出,阻塞非阻塞主要描述了你(调用者)和服务员(被调用者)之间是否需要等待对方。
接下来,我们再看同步异步的区别:
- 方式一:当服务员给你牛排时,他会告诉你“您好,您点的牛排已经做好了,请享用”。这就是同步方式。
- 方式二:当服务员把牛排放在号码牌对应的位置时,他不会告诉你任何信息。当你去取牛排时,你才知道牛排已经做好了。这就是异步方式。
从上面可以看出,同步异步主要描述了服务员(被调用者)和结果(牛排)之间是否有通知机制。
综合起来,我们可以得到四种组合:
- 阻塞+同步:服务员给我牛排,并告诉我“您好,您点的牛排已经做好了,请享用”。
- 阻塞+异步:不存在这种情况。
- 非阻塞+同步:服务员把我的号码放在显示屏上,并告诉我“您好,请注意显示屏上的号码变化”。
- 非阻塞+异步:服务员把我的号码放在显示屏上,并不告诉我任何信息。
从编程角度来看,在操作系统中常见的例子有:
- 阻塞+同步:read函数读取文件内容时会一直等待文件内容准备好,并返回读取结果。
- 阻塞+异步:不存在这种情况。
- 非阻塞+同步:select函数检查文件描述符集合中是否有可读写或异常事件发生时会立即返回结果,并通知哪些文件描述符发生了事件。
- 非阻塞+异步:signal函数注册信号处理函数时会立即返回,并不通知信号何时发生。
延伸阅读1:什么是异步
异步(Asynchronous, async)是与同步(Synchronous, sync)相对的概念。在我们学习的传统单线程编程中,程序的运行是同步的(同步不意味着所有步骤同时运行,而是指步骤在一个控制流序列中按顺序执行)。而异步的概念则是不保证同步的概念,也就是说,一个异步过程的执行将不再与原有的序列有顺序关系。
代码是自上而下同步执行的,既后面的代码必须等待前面的代码执行完才会执行,而异步执行则是将主线程中的某段代码交由子线程去执行,当交给子线程后,主线程就会继续执行后面代码,而不用等待子线程执行完成,异步是程序语言并行执行的一种手段,通常将耗时的任务交由子线程同时处理,从而提升整体任务耗时。