“阻塞”与"非阻塞"与"同步"与“异步"不能简单的从字面理解,提供一个从分布式系统角度的回答。
1.同步与异步
同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication)
所谓同步,就是在发出一个*调用*时,在没有得到结果之前,该*调用*就不返回。但是一旦调用返回,就得到返回值了。
换句话说,就是由*调用者*主动等待这个*调用*的结果。
而异步则是相反,*调用*在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在*调用*发出后,*被调用者*通过状态、通知来通知调用者,或通过回调函数处理这个调用。
典型的异步编程模型比如Node.js
举个通俗的例子:
你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。
而异步通信机制,书店老板直接告诉你我查一下啊,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你。在这里老板通过“回电”这种方式来回调。
2. 阻塞与非阻塞
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。
还是上面的例子,
你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了, 当然你也要偶尔过几分钟check一下老板有没有返回结果。
在这里阻塞与非阻塞与是否同步异步无关。跟老板通过什么方式回答你结果无关。
在处理 IO 的时候,阻塞和非阻塞都是同步 IO。
只有使用了特殊的 API 才是异步 IO。
对unix来讲:阻塞式I/O(默认),非阻塞式I/O(nonblock),I/O复用(select/poll/epoll)都属于同步I/O,因为它们在数据由内核空间复制回进程缓冲区时都是阻塞的(不能干别的事)。只有异步I/O模型(AIO)是符合异步I/O操作的含义的,即在1数据准备完成、2由内核空间拷贝回缓冲区后 通知进程,在等待通知的。
以Linux下 tcp socket编程为例:
阻塞就是 recv/read的时候 socket接收缓冲区要是有数据就读, 没数据我就一直睡觉赖着不走,直到有数据来了读完我才走。send/write的时候,要是发送缓冲区满了,没有空间继续发送了我也一直睡觉赖着不走,直到发送缓冲区腾出足够的空间让我把数据全部塞到发送缓冲区里我才走。(当然如果你通过setsockopt设置了读写超时,超时时间到了还是会返回-1和EAGAIN,不再睡觉等待)
各一句话
IO时进入内核代码没有立即返回,则直到返回前用户的进程代码一直处于「阻塞」状态。
从IO请求到数据复制到进程空间的过程中,若进程代码发生过阻塞,则IO过程是「同步」的,反之「异步」。
同步和异步仅仅是关于所关注的消息如何通知的机制。同步的情况下,是由处理消息者自己去等待消息是否被触发,而异步的情况下是由触发机制来通知处理消息者
阻塞和非阻塞应该是发生在消息的处理的时刻。阻塞其实就是等待,发出通知,等待结果完成。非阻塞属于发出通知,立即返回结果,没有等待过程。
关于同步异步、阻塞非阻塞的概念: 同步就是同步,异步就是异步! 目前应用中阻塞和非阻塞是针对同步应用而言。关于这些概念之间的关系的理解,可以通过以下几个例子来说明。
例子1:老板布置了一个调研任务,老板自己需要写一个调研报告。这个调研的一个子任务由同学A完成,老板最终需要将同学A的任务整合到自己的调研报告中。因为老板的调研报告需要用到同学A的调研结果,那么老板的调研报告就必须等到同学A调研完成以后才能完成。那么在整个调研的过程中,最终的调研报告和同学A的调研任务之间就是同步关系,因为两个任务之间有着时序的关系。
首先一个IO操作其实分成了两个步骤:发起IO请求和实际的IO操作,同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO,因此阻塞IO、非阻塞IO、IO服用、信号驱动IO都是同步IO,如果不阻塞,而是操作系统帮你做完IO操作再将结果返回给你,那么就是异步IO。阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。
看了一些这两个概念的解释,感觉不分场景的笼统理解是不对的,下面陈述一下我的理解:
这是两对概念,用在不同的语境会有一些不同的含义,不能一概而论。
整体来说,同步就是两种东西通过一种机制实现步调一致,异步是两种东西不必步调一致。
一、同步调用与异步调用:
在用在调用场景中,无非是对调用结果的不同处理。
我理解同步调用就是调用一但返回,就能知道结果,而异步是返回时不一定知道结果,还得通过其他机制来获知结果,如:
a. 状态
b. 通知
c. 回调函数
这里的同步调用不一定会阻塞,例如立即返回失败的结果。
而异步调用立即返回时,你还拿不到结果的。
二、同步线程与异步线程: