首先通过中文语义来看待这个问题,很多时候确实会混淆,并且在不同的语境中也有不同的意义。因此从I/O模型的角度来讨论,阻塞非阻塞跟同步异步是不同的概念。
阻塞非阻塞:
可以简单理解为需要做一件事能不能立即得到返回应答,如果不能立即获得返回,需要等待,那就阻塞了,否则就可以理解为非阻塞。
同步异步:
你总是做完一件再去做另一件,不管是否需要时间等待,这就是同步;异步呢则反之,你可以同时做几件事,并非一定需要一件事做完再做另一件事。同步简单理解成一问一答同步进行,异步可以简单理解为不必等一个问题有答了再去问另一个问题,尽管问,有答了再通知你。
也就是说,同步和异步仅仅是关于所关注的消息如何通知的机制。同步的情况下,是由处理消息者自己去等待消息是否被触发,而异步的情况下是由触发机制来通知处理消息者。阻塞和非阻塞应该是发生在消息的处理的时刻。阻塞其实就是等待,发出通知,等待结果完成。非阻塞属于发出通知,立即返回结果,没有等待过程。
知乎上的一个例子:
我去买一本书,立即买到了,这就是非阻塞;
如果恰好书店没有,我就等一直等到书店有了这本书买到了才走,这就是阻塞;
如果书店恰好没有,我就告诉书店老板,书来了告诉我一声让我来取或者直接送到我家,然后我就走了,这就是异步。
那同步呢? 前面两种情况,非阻塞和阻塞都可以称为同步。
如果说书店有这书,我还让老板通知我以后来取就没这个必要了。
这个例子反映在编程方面就是:用户进程调用系统调用。(用户进程对应要买书的我,内核对应书店老板,书对应数据资源data,买书就是一个系统调用了。)阻塞非阻塞与同步异步I/O机制,都是伴随计算机系统发展,用来解决一些问题的。
在unix网络编程中:
将I/O模型分为五类:阻塞式I/O(默认),非阻塞式I/O(nonblock),I/O复用(select/poll/epoll),信号驱动,异步I/O(AIO)。
∙ 阻塞 I/O模型:在这种模型下,若所调用的I/O 函数没有完成相关的功能就会使进程
挂起,直到相关数据到才会出错返回。如常见对管道设备、终端设备和网络设备进行读写时
经常会出现这种情况
∙ 非阻塞模型:在这种模型下,当请求的I/O 操作不能完成时,则不让进程睡眠,而且返回一个错误。非阻塞I/O 使用户可以调用不会永远阻塞的I/O 操作,如open、write和read。如果该操作不能完成,则会立即出错返回,且表示该I/O 如果该操作继续执行就会阻塞。
∙ I/O多路转接模型(I/O复用):在这种模型下,如果请求的I/O操作阻塞,且它不是真正阻塞I/O, 而是让其中的一个函数等待,在这期间,I/O 还能进行其他操作。select,poll和epoll函数,就是属于这种模型。
∙ 信号驱动 I/O 模型:在这种模型下,通过安装一个信号处理程序,系统可以自动捕获特定信号的到来,从而启动I/O。这是由内核通知用户何时可以启动一个I/O 操作决定的。
∙ 异步 I/O模型:在这种模型下,当一个描述符已准备好,可以启动I/O 时,进程会通知内核。现在,并不是所有的系统都支持这种模型。
阻塞式I/O,非阻塞式I/O,I/O复用都属于同步I/O。因为它们在数据由内核空间复制回进程缓冲区时都是阻塞的(不能干别的事)。只有异步I/O模型是符合异步I/O操作的含义的,即在数据准备完成、由内核空间拷贝回缓冲区后通知进程,在等待通知的这段时间里可以干别的事。
从网上找到一张解释很详细的图片:
(更多可以参考:UNIX网络编程)