首页 > 代码库 > 如何理解阻塞和非阻塞同步和异步

如何理解阻塞和非阻塞同步和异步

1.同步与异步

同步和异步关注的是消息通信机制,所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由调用者主动等待这个调用的结果。

而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果,而是在调用发出后,被调用者通过状态,通知机制来通知调用者,或通过回调函数处理这个调用。

举例:

你打电话问书店老板有没有《分布式系统》这本书,如果是同步通信机制,书店老板会说,你稍等,我去查一下,然后开始查啊查,等查好了(可能是5秒,也可能是一天)告诉你结果(返回结果)。

而异步通信机制,书店老板直接告诉你我查一下,查好了打电话给你,然后直接挂电话了(不返回结果)。然后查好了,他会主动打电话给你,在这里老板通过回电这种方式来回调。

 

2.阻塞与非阻塞:

阻塞与非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态。

阻塞调用时指调用结果返回之前,当前线程被挂起。调用线程只有在得到结果之后才会返回。

非阻塞调用时指在不能立刻得到结果之前,该调用不会阻塞当前线程。

 

还是上面的例子:

你打电话问书店老板有没有《分布式系统》这本书,你如果是阻塞式调用,你会一直把自己挂起,直到得到这本书有没有的结果,如果是非阻塞式调用,你不管老板有没有告诉你,你自己先一边玩去了,当然你也要偶尔过几分钟check以下老板有没有返回结果。

 

在这里阻塞与非阻塞与是否同步异步无关,跟老板通过什么方式回答你结果无关。

 

在处理IO的时候,阻塞和非阻塞都是同步IO

只有使用了特殊的API才是异步IO

 

五种unix下可用的I/O模型:

阻塞是I/O:

非阻塞是I/O:

I/O复用:

信号驱动I/O

异步I/Oposisaio系列函数)

 

阻塞是I/0模型:默认情况下,所有套接字都是阻塞的,一个输入操作通常包括两个不同阶段:

1.     等待数据尊卑好

2.     从内核向进程复制数据

对于一个套接字上的输入操作,第一步通常涉及等待数据从中到达。当所有等待分组到达时,它被复制到内核中的某个缓冲区中。第二步就是把数据从内核缓冲区复制到应用程序缓冲区中。下面以阻塞套接字的recvfrom的调用图来说明阻塞。

技术分享

标红的这部分过程就是阻塞,直到阻塞结束recvfrom才能返回。

 

非阻塞式I/O:以下这句话很重要:进程把一个套接字设置成非阻塞是在通知内核,当所请求的I/O操作非得把本进程投入睡眠才能完成时,不要把进程投入睡眠,而是返回一个错误。看看非阻塞的套接字recvfrom操作如何进行的。



技术分享


可以看出recvfrom总是立即返回。

/O多路复用:虽然I/O多路复用的函数也是阻塞的,但是其与以上两种还是有不同的,I/O多路复用是阻塞在selectepoll这样的系统调用之上,而没有阻塞在真正的I/O系统调用如recvfrom之上。如图



技术分享

信号驱动式I/O


技术分享

异步I/O:这类函数的工作机制是告知内核启动某个操作,并让内核在整个操作(包括将数据从内核拷贝到用户空间)完成后通知我们。如图:


技术分享

注意红线标记处说明在调用时就可以立马返回,等函数操作完成会通知我们。

等等,大家一定要问了,同步这个概念你怎么没涉及啊?别急,您先看总结。其实前四种I/O模型都是同步I/O操作,他们的区别在于第一阶段,而他们的第二阶段是一样的:在数据从内核复制到应用缓冲区期间(用户空间),进程阻塞于recvfrom调用。相反,异步I/O模型在这两个阶段都要处理。

 

阻塞与非阻塞的区别就是:是否会阻塞发起IOprocess,同步与异步的区别就是process在发起IO后,内核准备好数据前,是否在做其他事情。但是non-blocking IO虽然没有阻塞process,但是我觉着在processnon-blocking IO是在一个while循环中不停的发起IO,没做其他事情,所以属于同步IO

 

首先一个IO操作其实分成了两个步骤:发起IO请求和实际的IO操作,同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO,因此阻塞IO、非阻塞IOIO服用、信号驱动IO都是同步IO,如果不阻塞,而是操作系统帮你做完IO操作再将结果返回给你,那么就是异步IO。阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO

 

unix来讲:阻塞式I/O(默认),非阻塞式I/O(nonblock)I/O复用(select/poll/epoll)都属于同步I/O,因为它们在数据由内核空间复制回进程缓冲区时都是阻塞的(不能干别的事)。只有异步I/O模型(AIO)是符合异步I/O操作的含义的,即在1数据准备完成、2由内核空间拷贝回缓冲区后通知进程,在等待通知的这段时间里可以干别的事。

 

老张爱喝茶,废话不说,煮开水。

出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。

1 老张把水壶放到火上,立等水开。(同步阻塞)

老张觉得自己有点傻

2 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)

老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。

3 老张把响水壶放到火上,立等水开。(异步阻塞)

老张觉得这样傻等意义不大

4 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)

老张觉得自己聪明了。

 

 

所谓同步异步,只是对于水壶而言。

普通水壶,同步;响水壶,异步。

虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。

同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。

 

所谓阻塞非阻塞,仅仅对于老张而言。

立等的老张,阻塞;看电视的老张,非阻塞。

情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。

 

看电视节目的时候还要留神听水壶声,你确定这是非阻塞吗?

分多一个线程用来等待响应,主线程可以处理其他响应先。

 


本文出自 “刘小兔” 博客,转载请与作者联系!

如何理解阻塞和非阻塞同步和异步