不管我们在系统设计还是编码开发的过程中,程序猿们在相互技术博弈的过程中经常会谈起“阻塞”“非阻塞”“同步”“异步”这些专业名词,那么它们到底有什么区别?你是不是都理解搞懂了呢?接下来我们对“阻塞”“非阻塞”与“同步”“异步”分别来介绍讲解。
===========================================================
“阻塞”“非阻塞”关注的是程序在等待调用结果,阻塞调用是指调用结果返回之前,当前进程会被挂起,只有在得到结果之后才会返回,非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前进程。
举个栗子:
你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己“挂起”,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边去玩了,当然你也要偶尔过几分钟询问一下老板有没有返回结果。
“同步”“异步”关注的是消息通信机制,“同步”在发出调用后,在没有得到结果之前,该调用就不返回,但是一旦调用返回,就得到对应的返回值,也就是调用者一直等待这个结果,“异步”在发出调用后,这个调用就直接返回了,但是没有返回结果,也就是调用者不会立刻得到结果,而是在调用后,被调用者通过回调函数或者异步通知的方式来返回调用者结果。
举个栗子:
你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,”我查一下",然后开始查啊查,等查好了告诉你结果,而异步通信机制,书店老板直接告诉你我查一下,查好了打电话给你,然后直接挂电话了,然后查好了,他会主动打电话给你。
===========================================================
是不是感觉“阻塞”“非阻塞”与“同步”“异步”是2个概念的东西?那我们接着往下说。
我们在某些资料中可以找到有关进程间通信的一些解释,进程间通信是通过 send()和receive()两种基本操作完成的,消息的传递有可能是阻塞的或非阻塞的,也被称为同步或异步的。不同类型的发送/接受方式如下:
阻塞式发送(blocking send),发送方调用send()后一直阻塞,直到消息被接受方进程收到。
非阻塞式发送(nonblocking send),发送方调用send()后,立即就可以其他操作。
阻塞式接收(blocking receive),接收方调用receive()后一直阻塞,直到消息到达可用。
非阻塞式接受(nonblocking receive),接收方调用receive()后,得到一个结果或空值,并不会阻塞。
也就是说,从进程级通信的维度来看, “阻塞”“非阻塞”与“同步”“异步”似乎是一个概念,只需要针对发送方和接收方作区分对待即可,那我们为什么还要进行区分它们,到底它们之间有什么区别?
那我们再从IO System Call的视角再来看看,首先一定会问为什么“阻塞”“非阻塞”会与IO System Call有所关系,因为我们要让一个进程进入等待状态,可以主动调用System Call,而System Call又涉及到I/O操作,不能立即完成,于是内核将会将该进程置为等待状态,调度其他进程的运行,等到它所请求的I/O操作完成以后,再将其状态更改回ready。
大部分操作系统默认为阻塞式的System Call接口,因为阻塞式的调用,使得代码的编写更容易,但大部分操作系统也会提供非阻塞的System Call接口,非阻塞调用不会挂起调用程序,而是会立即返回一个值,表示有多少bytes的数据被成功读取或写入,而非阻塞System Call的另一个替代品就是异步System Call,与非阻塞类似,它们两者的区别就是非阻塞System Call的read()操作立即返回的是任何可以立即拿到的数据,可以是完整的结果,也可以是不完整的结果,还可以是一个空值,而异步System Call的 read()操作返回的结果必须是完整的,但是这个操作完成的通知可以延迟到将来的一个时间点。
===========================================================
总结:“阻塞”“非阻塞”“同步”“异步”从进程层面来看,它们基本相同,仅需注意区分对象是发送方还是接受方即可,而从IO系统调用层面来看,“非阻塞”与“异步”还是存在一定的差异,它们虽然都不会阻塞进程,但是返回结果的方式和内容还是有所差别,我们可以通过非阻塞系统调用来可以减少内存消耗以及提升系统性能。
注:文章均原创,部分图片和文字来源于网络,若涉及版权,请联系作者,将在第一时间注明出处,谢谢。