怎样理解阻塞非阻塞与同步异阻塞和同步的区别别

C++(115)
SOCKET(18)
/question/
著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
作者:愚抄
链接:/question//answer/
来源:知乎
老张爱喝茶,废话不说,煮开水。
出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
1 老张把水壶放到火上,立等水开。(同步阻塞)
老张觉得自己有点傻
2 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)
老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。
3 老张把响水壶放到火上,立等水开。(异步阻塞)
老张觉得这样傻等意义不大
4 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)
老张觉得自己聪明了。
所谓同步异步,只是对于水壶而言。
普通水壶,同步;响水壶,异步。
虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。
同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。
所谓阻塞非阻塞,仅仅对于老张而言。
立等的老张,阻塞;看电视的老张,非阻塞。
情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。
——来源网络,作者不明。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:56496次
积分:1579
积分:1579
排名:第18900名
原创:63篇
转载:238篇
(1)(1)(11)(5)(1)(9)(11)(14)(16)(70)(3)(6)(8)(10)(1)(13)(6)(11)(43)(7)(15)(5)(8)(3)(2)(6)(2)(18)线程中的同步与异步,阻塞和非阻塞
[问题点数:20分,结帖人wumin]
线程中的同步与异步,阻塞和非阻塞
[问题点数:20分,结帖人wumin]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
本帖子已过去太久远了,不再提供回复功能。博客访问: 4046666
博文数量: 676
博客积分: 2150
博客等级: 上尉
技术积分: 11843
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: LINUX
一、同步与异步
同步/异步, 它们是消息的通知机制
1. 概念解释
所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。
按照这个定义,其实绝大多数函数都是同步调用(例如sin isdigit等)。
但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。
最常见的例子就是 SendMessage。
该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。
当对方处理完毕以后,该函数才把消息处理函数所返回的值返回给调用者。
异步的概念和同步相对。
当一个异步过程调用发出后,调用者不会立刻得到结果。
实际处理这个调用的部件是在调用发出后,
通过状态、通知来通知调用者,或通过回调函数处理这个调用。
以 Socket为例,
当一个客户端通过调用 Connect函数发出一个连接请求后,调用者线程不用等待结果,可立刻继续向下运行。
当连接真正建立起来以后,socket底层会发送一个消息通知该对象。
C. 三种返回结果途径&
执行部件和调用者可以通过三种途径返回结果:
a. & 状态、
b. & 通知、
c. & 回调函数。
可以使用哪一种依赖于执行部件的实现,除非执行部件提供多种选择,否则不受调用者控制。
a. 如果执行部件用状态来通知,
& & 那么调用者就需要每隔一定时间检查一次,效率就很低
& & 有些初学多线程编程的人,总喜欢用一个循环去检查某个变量的值,这其实是一种很严重的错误。
b.&如果是使用通知的方式,
& & 效率则很高,因为执行部件几乎不需要做额外的操作。
c. 至于回调函数,
& & 和通知没太多区别。
2. 举例说明
理解这两个概念,可以用去银行办理业务(可以取钱,也可以存钱)来比喻:
当到银行后,
.可以去ATM机前排队等候 & & & & & & & & & & & & & & & &-- (排队等候)就是同步等待消息
.可以去大厅拿号,等到排到我的号时,
&柜台的人会通知我轮到我去办理业务. & & & & & & &-- (等待别人通知)就是异步等待消息.
在异步消息通知机制中,
等待消息者(在这个例子中就是等待办理业务的人)往往注册一个回调机制,
在所等待的事件被触发时由触发机制(在这里是柜台的人)通过某种机制(在这里是写在小纸条上的号码)
找到等待该事件的人.
在select/poll 等IO 多路复用机制中就是fd,
当消息被触发时,触发机制通过fd 找到处理该fd的处理函数.
3. 在实际的程序中,
同步消息通知机制:就好比简单的read/write 操作,它们需要等待这两个操作成功才能返回;
& & & & & & & & & 同步, 是由处理消息者自己去等待消息是否被触发;
异步消息通知机制:类似于select/poll 之类的多路复用IO 操作,
& & & & & & & & & 当所关注的消息被触发时,由消息触发机制通知触发对消息的处理.
& & & & & & & & & 异步, 由触发机制来通知处理消息者;
还是回到上面的例子,
轮到你办理业务, 这个就是你关注的消息,
而办理什么业务, 就是对这个消息的处理,
两者是有区别的.
而在真实的IO 操作时: 所关注的消息就是 & & 该fd是否可读写,
& & & & & & & & & & &而对消息的处理是 & & 对这个fd 进行读写.
同步/异步仅仅关注的是如何通知消息,它们对如何处理消息并不关心,
好比说,银行的人仅仅通知你轮到你办理业务了,
而办理业务什么业务(存钱还是取钱)他们是不知道的.
二、阻塞与非阻塞
阻塞/非阻塞, 它们是程序在等待消息(无所谓同步或者异步)时的状态.
1. 概念解释
阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。
有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。
对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。
socket接收数据函数recv是一个阻塞调用的例子。
当socket工作在阻塞模式的时候, 如果没有数据的情况下调用该函数,则当前线程就会被挂起,直到有数据为止。
非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
C. 对象的阻塞模式和阻塞函数调用
对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但是并不是一一对应的。
阻塞对象上可以有非阻塞的调用方式,我们可以通过一定的API去轮询状态,
在适当的时候调用阻塞函数,就可以避免阻塞。
而对于非阻塞对象,调用特殊的函数也可以进入阻塞调用。函数select就是这样的一个例子。
2. 举例说明
继续上面的那个例子,
不论是排队等待,还是使用号码等待通知,
如果在这个等待的过程中,
. 等待者除了等待消息之外不能做其它的事情,那么该机制就是阻塞的,
& 表现在程序中,也就是该程序一直阻塞在该函数调用处不能继续往下执行.
. 相反,有的人喜欢在银行办理这些业务的时候一边打打电话发发短信一边等待,这样的状态就是非阻塞的,
& 因为他(等待者)没有阻塞在这个消息通知上,而是一边做自己的事情一边等待.
三、易混淆的点
很多人也会把异步和非阻塞混淆,
因为异步操作一般都不会在真正的IO 操作处被阻塞,
比如如果用select 函数,当select 返回可读时再去read 一般都不会被阻塞
就好比当你的号码排到时一般都是在你之前已经没有人了,所以你再去柜台办理业务就不会被阻塞.
可见,同步/异步与阻塞/非阻塞是两组不同的概念,它们可以共存组合,
而很多人之所以把同步和阻塞混淆,我想也是因为没有区分这两个概念,
比如阻塞的read/write 操作中,其实是把消息通知和处理消息结合在了一起,
在这里所关注的消息就是fd 是否可读/写,而处理消息则是对fd 读/写.
当我们将这个fd 设置为非阻塞的时候,read/write 操作就不会在等待消息通知这里阻塞,
如果fd 不可读/写则操作立即返回.
四、同步/异步与阻塞/非阻塞的组合分析
_______阻塞____________________非阻塞_____
同步 | 同步阻塞 & & & & & & &同步非阻塞
异步 | 异步阻塞 & & & & & & &异步非阻塞
同步阻塞形式:
& 效率是最低的,
& 拿上面的例子来说,就是你专心排队,什么别的事都不做。
& 实际程序中
& 就是未对fd 设置O_NONBLOCK 标志位的read/write 操作,
异步阻塞形式:
& 如果在银行等待办理业务的人采用的是异步的方式去等待消息被触发,也就是领了一张小纸条,
& 假如在这段时间里他不能离开银行做其它的事情,那么很显然,这个人被阻塞在了这个等待的操作上面;
& 异步操作是可以被阻塞住的,只不过它不是在处理消息时阻塞,而是在等待消息被触发时被阻塞.
& 比如select 函数,
& 假如传入的最后一个timeout 参数为NULL,那么如果所关注的事件没有一个被触发,
& 程序就会一直阻塞在这个select 调用处.
同步非阻塞形式:
& 实际上是效率低下的,
& 想象一下你一边打着电话一边还需要抬头看到底队伍排到你了没有,
& 如果把打电话和观察排队的位置看成是程序的两个操作的话,
& 这个程序需要在这两种不同的行为之间来回的切换,效率可想而知是低下的;
& 很多人会写阻塞的read/write 操作,
& 但是别忘了可以对fd 设置O_NONBLOCK 标志位,这样就可以将同步操作变成非阻塞的了;
异步非阻塞形式:
& 效率更高,
& 因为打电话是你(等待者)的事情,而通知你则是柜台(消息触发机制)的事情,
& 程序没有在两种不同的操作中来回切换.
& 比如说,这个人突然发觉自己烟瘾犯了,需要出去抽根烟,
& 于是他告诉大堂经理说,排到我这个号码的时候麻烦到外面通知我一下(注册一个回调函数),
& 那么他就没有被阻塞在这个等待的操作上面,自然这个就是异步+非阻塞的方式了.
& 如果使用异步非阻塞的情况,
& 比如aio_*组的操作,当发起一个aio_read 操作时,函数会马上返回不会被阻塞,
& 当所关注的事件被触发时会调用之前注册的回调函数进行处理,
九二,见龙在田,利见大人。
【白话】九二,龙已出现在地上,利于出现德高势隆的大人物。
《象》曰:“见龙在田”,德施普也。
【白话】《象辞》说:“龙已出现在地上”,犹如阳光普照,天下人普遍得到恩惠。
阅读(41407) | 评论(5) | 转发(15) |
相关热门文章
给主人留下些什么吧!~~
看了你的文章后,感觉这里面的概念还是有些自相矛盾的地方,我凭我的理解梳理了一下:/albert1017/p/3914149.html,欢迎指正
connnect操作实际上是可以工作在同步/异步,阻塞/非阻塞的四种组合中的一种,你理解的应该是同步阻塞模式,实际上另三种都是不用等内核层返回结果给用户层后,程序才能继续向下运行。这篇文章讲了这四种组合:http://blog.chinaunix.net/uid--id-3754543.html另外我对socket中应用这四种组合做了专门的示例详解,有兴趣也可以一并看看。
“当一个客户端通过调用&Connect函数发出一个连接请求后,调用者线程不用等待结果,可立刻继续向下运行。”我的理解connect会进行三次握手,首先发SYN包给服务器,客户端socket进入SYN_SEND状态,等待服务端的ACK,如果收到ACK,立刻进入ESTABLISHED状态,两端可以通信了。如果这个过程出现错误,则错误都会以返回值的形式返回调用者。我这里不太明白你说的“调用者不用等待结果,直接向下执行”是什么意思??大侠能否解释下
请登录后评论。同步/异步与阻塞/非阻塞的区别
同步和异步仅仅是关于所关注的消息如何通知的机制,而不是处理消息的机制.也就是说,
同步的情况下, & &
是由处理消息者自己去等待消息是否被触发,
而异步的情况下 & 是由触发机制来通知处理消息者
硬件上下文切换
每个进程都拥有自己的内存空间,CPU任何时间只能运行一个进程.
运行之前,每个进程需要将内存状态复制到CPU的寄存器才能工作。这种复制就是进程的上下文切换
二种切换都会导致成本升高
1.进程内存-CPU寄存器相互切换 硬件上下文 解决:上下文切换一般都是由阻塞引起的,所以使用非阻塞
2.进程二种运行状态的切换 用户态-内核态 解决:减少不避要的系统调用。
阻塞的特点:进程睡眠
如果条件未就绪,'你'必须死等它就绪;进程睡眠(睡眠的缺点就是会让出CPU控制权)
非阻塞:如果条件未就绪,'你'可以转身作别的事情;进程可以作任何想做的事情,不过通常是低效的轮询。(轮询的特点是CPU寄存器一直被当前进程使用。轮询不是一种好的方式,可以使用wait/notify机制)
以这种理解方式,阻塞/非阻塞只对同步操作有意义;异步I/O总是意味着进程不会因为I/O陷入睡眠。
阻塞非阻塞示例:
比如一个人去银行办业务,拿到流水号之后,一边抬头看显示屏幕上当前显示的流水号一边打电话这就是同步非阻塞。(当前进程在等待的过程中可以做其它事情,注意,如果将柜台触发流水号理解为消息通知的话,就能避免用户不停的在二件事情上来回切换,此时用户只需要打你的电话就OK了,不用再抬头看流水号是否轮到了自己,这件事情交给了银行柜台去做,因为柜台与用户是二个主体各做一件事情,这不会象用户一个人同时做二件事情而引起低效轮询)
一个广义概念的read/write应该包含的时间:
数据就绪的时间+数据读写的时间
注:进程等待数据就绪,可以阻塞(傻等),也可以非阻塞(同时做其它事情)。进程进行数据读写可以使用阻塞或非阻塞的方法。
select是同步还是异步:
经常看到一些技术博客或书籍讲IO的多路就绪通知中的select方式是异步阻塞。
1.如果按照同步与异步只取决于消息通知,不包括处理消息的话,select是异步的方式。示例:只要柜台通知了我就算异步,至于办理什么业务即如何处理消息不参与到同步异步的划分。此时select是异步阻塞方式。
2.如果按照UNP的划分的话,同步/异步不仅仅包括消息通知,还包括了对消息的处理。select并没有什么神秘的地方,它只是监控了多个fd的状态而不是一个。select实际上完成的只是read/write的第一部分:等待条件就绪;唯一的改进是可以等待多个条件。"select
read/write"的调用形式容易产生"系统通知我条件就绪"的假象,可实际上你不过是在条件就绪的时候醒来,然后仍然亲自动手完成了数据复制的操作。
select通知进程之后,进程还要切到内核态调用一些系统函数来读写数据,比如NIO中的Channel在获得相应的Channel注册的事件已经触发之后,还要负责读写数据。所以,如果基于UNP的划分,NIO是属于同步非阻塞的方式,read/write、read
+ NON_BLOCK、select、signal driven I/O 都属于同步I/O;
它们的共同特点是:将数据从内核空间复制到到用户空间的这个操作,是由用户空间的代码显式发起的。
select示例:
柜台R:只能取款
柜台W:只能存款
read: 亲自在柜台R排队(进程睡眠) + 取款
write: 亲自在柜台W排队(进程睡眠) + 存款
select + read/write : 亲自同时在R、W两个柜台排队(进程睡眠) + (存款|取款|存款+取款)
注:我觉得二种见解都正确,角度不同而已。
什么是异步:
告诉心腹小弟要取款若干,然后忙别的事情;小弟取款完毕将其如数奉上。只有AIO属于异步I/O;内核不露声色的将数据从内核空间复制到用户空间,然后通知进程。(NIO在就绪之后,进程还要切换到内核态调用系统函数将数据读写到用户态的内存空间。AIO直接告诉进程你可以操作用户态空间里的数据了。)
异步示例:交代要做的事情,然后忙其他的事情;'别人'(OS)会充当你的跑腿,在全部做完你交待的事情,然后通知你(callback);比如你交待取钱,可以做其它事情,他最终取完钱会把钱交到你的手上。
参考博客:/converse/archive//82879.html
-------------------------------------------------------------------------------
之前的想法:
读写方法可以分为阻塞与非阻塞二类。NIO中Channel的读写方法是非阻塞的,Channel 是一个全新的原始 I/O
抽象。Channel用来表示以前的InputStream,OutputStream表示的数据的源与目的。Channel通过Buffer中转数据。而传统的IO类的读写操作默认是阻塞方式的。
阻塞的读方法中,读阻塞与读方法有关,读方法的参数决定了要读多少数据,如果没有读满, 就会一直阻塞.
直到读满返回。
写阻塞类似,具体也取决于写方法的参数。
对于阻塞而引起的等待的问题,解决方法有二种,一种是通过多执行流来处理,比如多线程,多进程(优点:多线程、多进程可以有效的利用CPU资源。缺点:代价就是多进程的大量内存开销,多线程的上下文切换及创建线程本身的开销).
另一种解决办法JDK中的NIO,减少线程上下文的切换。在一个线程里处理多个事情,但是会导致CPU忙于应付轮询,这是低效的。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
您的访问请求被拒绝 403 Forbidden - ITeye技术社区
您的访问请求被拒绝
亲爱的会员,您的IP地址所在网段被ITeye拒绝服务,这可能是以下两种情况导致:
一、您所在的网段内有网络爬虫大量抓取ITeye网页,为保证其他人流畅的访问ITeye,该网段被ITeye拒绝
二、您通过某个代理服务器访问ITeye网站,该代理服务器被网络爬虫利用,大量抓取ITeye网页
请您点击按钮解除封锁&}

我要回帖

更多关于 异步和非阻塞的区别 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信