对阻塞、非阻塞、同步、异步的个人理解

这四点在开发中经常遇到,但经常看的有些懵逼,似懂非懂的样子。其实要讨论这四点的区别,要分不同应用场景来看。

1.进程通信场景

在进程通信中,这四个词基本都是一个含义。比如我们常用的socket网络编程,其目的就是为了实现客户端与服务器的通信,这其实就可以看作是两个进程的通信。

进程间的通信是通过 send() 和 receive() 两种基本操作完成的。具体如何实现这两种基础操作,存在着不同的设计。 消息的传递有可能是阻塞的或非阻塞的–也被称为同步或异步的。

阻塞式发送(blocking send):发送方进程会被一直阻塞, 直到消息被接受方进程收到。

非阻塞式发送(nonblocking send):发送方进程调用 send() 后, 立即就可以其他操作。

阻塞式接收(blocking receive):接收方调用 receive() 后一直阻塞, 直到消息到达可用。

非阻塞式接受(nonblocking receive):接收方调用 receive() 函数后, 要么得到一个有效的结果,要么得到一个空值, 即不会被阻塞。

参考自: https://www.zhihu.com/question/19732473/answer/241673170

所以说,从进程级通信的场景来看, 阻塞和同步是一个意思,非阻塞和异步也是一个意思,只是我们需要针对发送方和接收方作区分对待。

2.IO调用场景

IO调用更像是一种进程的通信方式。我们两个进程(也可以说客户端和服务器)通过socket建立了连接,不管是TCP还是UDP协议,最终的目的是要实现通信。socket只解决了如何建立通信,但具体的通信手段却需要通过IO读写来完成。(下面的客户端就假定为进程A,服务端就假定为进程B)

比如要客户端发送一句话,就必须将这句话通过调用系统IO转换为字节数据,然后通过IO发送,服务端通过IO流接收后再调用系统IO将其转换成一句话,这才是一次通信。

又比如客户端要发送一个文件到服务端,那么文件也需要通过调用系统IO将其转换为IO流,再传递给服务端,服务端再调用系统IO将其读取出来转换为文件。

所以,从IO调用的场景来讨论,阻塞/非阻塞、同步/异步的意思又有所区别,总的来说分为三种状态来讨论(同步阻塞、同步非阻塞、IO多路复用(异步阻塞)、异步(非阻塞)):

  • 同步阻塞:进程A给进程B发送消息(IO操作)时,进程B也许因为一些原因没有完成这条消息的处理,迟迟没有给进程A回复。这时候进程A没有收到进程B的回复,那么进程A无法完成一个完成的IO操作(这里涉及操作系统中用户态和内核态的知识,暂不做扩展),于是就进入等待状态。由于等待过程中进程A无法做其他事,所以就称其处于阻塞状态。
  • 同步非阻塞:进程A给进程B发送消息(IO操作)时,进程B收到后如果消息没有处理完成也要立即返回一个信息,哪怕是空信息或者部分信息也要返回,那么进程A就收到的如果不是完成的信息,就去做其他事情,然后过一段时间再请求(轮询),直到收到进程B正确的消息后再执行对应的操作(这一过程就是自旋)。
  • IO多路复用(异步阻塞):这种方式是为了解决同步非阻塞的轮询问题。进程A发送多条消息后,操作系统会创建一个选择器,用于存储进程B每次返回的消息,进程A要获取返回的消息就去这个选择器中查询,没有查询到就去执行其他事情,不过进程A查询选择器的过程是阻塞的,进程A查询时,其余进程不能够查询。这种方式其实就相当于将进程A对进程B的轮询换到了进程A对选择器的轮询,相对而言效率会更高。
  • 异步(非阻塞):异步和同步非阻塞优点相似。区别就在于,进程A并不会去等待消息的返回,而是发送完消息后立即去做其他事情,进程B必须要在消息处理完成后返回完整正确的信息,当进程B返回消息后,由操作系统来通知进程A执行对应的操作。

只是一些个人的理解,并非完全正确,不过可以帮助加深对这四种方式的理解。

猜你喜欢

转载自blog.csdn.net/c_o_d_e_/article/details/112559126