抑郁症健康,内容丰富有趣,生活中的好帮手!
抑郁症健康 > 同步/异步 阻塞/非阻塞区别

同步/异步 阻塞/非阻塞区别

时间:2019-10-27 16:38:29

相关推荐

我喜欢用自己的语言通过联系现实生活中的一些现象解释一些概念,当我能做到这一点时,说明我已经理解了这个概念.今天要解释的概念是:同步/异步与阻塞/非阻塞的区别.

这两组概念常常让人迷惑,因为它们都是涉及到IO处理,同时又有着一些相类似的地方.

首先来解释同步和异步的概念,这两个概念与 消息的通知机制有关.

举个例子,比如我去银行办理业务,可能选择排队等候,也可能取一个小纸条上面有我的号码,等到排到我这一号时由柜台的人通知我轮到我去办理业务了.

前者(排队等候)就是同步等待消息,而后者(等待别人通知)就是异步等待消息.在异步消息处理中,等待消息者(在这个例子中就是等待办理业务的人)往往注册一个回调机制,在所等待的事件被触发时由触发机制(在这里是柜台的人)通过某种机制(在这里是写在小纸条上的号码)找到等待该事件的人.

而在实际的程序中,同步消息处理就好比简单的read/write操作,它们需要等待这两个操作成功才能返回;而异步处理机制就是类似于select/poll之类的多路复用IO操作,当所关注的消息被触发时,由消息触发机制通知触发对消息的处理.

其次再来解释一下阻塞和非阻塞,这两个概念与 程序等待消息(无所谓同步或者异步)时的状态有关.

继续上面的那个例子,不论是排队还是使用号码等待通知,如果在这个等待的过程中,等待者除了等待消息之外不能做其它的事情,那么该机制就是阻塞的,表现在程序中,也就是该程序一直阻塞在该函数调用处不能继续往下执行.相反,有的人喜欢在银行办理这些业务的时候一边打打电话发发短信一边等待,这样的状态就是非阻塞的,因为他(等待者)没有阻塞在这个消息通知上,而是一边做自己的事情一边等待.但是需要注意了,第一种同步非阻塞形式实际上是效率低下的,想象一下你一边打着电话一边还需要抬头看到底队伍排到你了没有,如果把打电话和观察排队的位置看成是程序的两个操作的话,这个程序需要在这两种不同的行为之间来回的切换,效率可想而知是低下的;而后者,异步非阻塞形式却没有这样的问题,因为打电话是你(等待者)的事情,而通知你则是柜台(消息触发机制)的事情,程序没有在两种不同的操作中来回切换.

很多人会把同步和阻塞混淆,我想是因为很多时候同步操作会以阻塞的形式表现出来,比如很多人会写阻塞的read/write操作,但是别忘了可以对fd设置O_NONBLOCK标志位,这样就可以将同步操作变成非阻塞的了;同样的,很多人也会把异步和非阻塞混淆,因为异步操作一般都不会在真正的IO操作处被阻塞,比如如果用select函数,当select返回可读时再去read一般都不会被阻塞,就好比当你的号码排到时一般都是在你之前已经没有人了,所以你再去柜台办理业务就不会被阻塞.

可见,同步/异步与阻塞/非阻塞是两组不同的概念,它们可以共存组合,也可以参见这里:

/developerworks/cn/linux/l-async/

----------------------------------------- 分割线 ------------------------------------------------------

昨晚写完这篇文章之后,今早来看了看反馈,同时再自己阅读了几遍,发现还是有一些地方解释的不够清楚,在这里继续补充完善一下我的说法,但愿没有越说越糊涂.

同步和异步:上面提到过, 同步和异步仅仅是关于所关注的消息如何通知的机制,而不是处理消息的机制.也就是说, 同步的情况下,是由处理消息者自己去等待消息是否被触发,而异步的情况下是由触发机制来通知处理消息者,所以在异步机制中,处理消息者和触发机制之间就需要一个连接的桥梁,在我们举的例子中这个桥梁就是小纸条上面的号码,而在select/poll等IO多路复用机制中就是fd,当消息被触发时,触发机制通过fd找到处理该fd的处理函数.

请注意理解 消息通知和处理消息这两个概念,这是理解这个问题的关键所在.还是回到上面的例子,轮到你办理业务这个就是你关注的消息,而去办理业务就是对这个消息的处理,两者是有区别的.而在真实的IO操作时,所关注的消息就是该fd是否可读写,而对消息的处理就是对这个fd进行读写.同步/异步仅仅关注的是如何通知消息,它们对如何处理消息并不关心,好比说,银行的人仅仅通知你轮到你办理业务了,而如何办理业务他们是不知道的.

而很多人之所以把同步和阻塞混淆,我想也是因为没有区分这两个概念,比如阻塞的read/write操作中,其实是把消息通知和处理消息结合在了一起,在这里所关注的消息就是fd是否可读/写,而处理消息则是对fd读/写.当我们将这个fd设置为非阻塞的时候,read/write操作就不会在等待消息通知这里阻塞,如果fd不可读/写则操作立即返回.

很多人又会问了,异步操作不会是阻塞的吧?已经通知了有消息可以处理了就一定不是阻塞的了吧?

其实 异步操作是可以被阻塞住的,只不过通常不是在处理消息时阻塞,而是在等待消息被触发时被阻塞.比如select函数,假如传入的最后一个timeout参数为NULL,那么如果所关注的事件没有一个被触发,程序就会一直阻塞在这个select调用处.而如果使用异步非阻塞的情况,比如aio_*组的操作,当我发起一个aio_read操作时,函数会马上返回不会被阻塞,当所关注的事件被触发时会调用之前注册的回调函数进行处理,具体可以参见我上面的连接给出的那篇文章.回到上面的例子中,如果在银行等待办理业务的人采用的是异步的方式去等待消息被触发,也就是领了一张小纸条,假如在这段时间里他不能离开银行做其它的事情,那么很显然,这个人被阻塞在了这个等待的操作上面;但是呢,这个人突然发觉自己烟瘾犯了,需要出去抽根烟,于是他告诉大堂经理说,排到我这个号码的时候麻烦到外面通知我一下(注册一个回调函数),那么他就没有被阻塞在这个等待的操作上面,自然这个就是异步+非阻塞的方式了.

posted on -05-13 22:11 那谁 阅读(26895) 评论(37) 编辑收藏引用 所属分类: 网络编程 、服务器设计 、Linux/Unix

评论

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

bu cuo -05-13 22:59 | tiny

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

我这个笨还是想不通

排列等待是等待,也是等别人通知你呀,站在你前面那个人的事办完了,还不是就通知到你了。

而那个小纸条是通知,也还是等待啊,还不是等一个个人处理完,最后你前一个处理,就轮到你了。

不是一样啊?没什么分别呀。只不过人排列的顺序变成了号码排列的顺序。 -05-13 23:42 | ttplay

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

@ttplay

我的理解是:

同步的时候,不是站在你前面的人通知你,是你自己得看着你前面还有没有人。

而小纸条就不一样了,你拿了纸条就不用管了,出去溜达都可以,反正到时候有人会叫你。

-05-14 09:12 | Sunshine Alike

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

我觉得IO复用select/epoll那个应该不算异步吧,异步(AIO)是指read/write完成后操作系统会回调用户空间的指定回调方法,而select/epoll只是一个有事件就绪的通知,没有这个回调过程,需要你自己主动调用read/write -05-14 09:33 | bachmozart

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

类比很恰当,确实让我又清晰了不少。

好文,作者好人。 -05-14 11:31 | abettor

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

@ttplay

排队等待是处理消息者自己等待,取小纸条是由别人通知你.

-05-14 13:09 | 那谁

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

我的理解:

同步: '你'亲自办这件事

异步: 交代要做的事情,然后忙其他的事情;'别人'(内核)会充当你的跑腿,在条件就绪后将这事办成,然后通知你(callback);

阻塞: 如果条件未就绪,'你'必须死等它就绪;进程睡眠

非阻塞:如果条件未就绪,'你'可以转身作别的事情;进程可以作任何想做的事情,不过通常是低效的轮询。

以这种理解方式,阻塞/非阻塞只对同步操作有意义;异步I/O总是意味着进程不会因为I/O陷入睡眠。

将" select"归类为异步+blocking不妥,select实际上完成的只是read/write的第一部分:等待条件就绪;唯一的改进是可以等待多个条件。"select + read/write"的调用形式容易产生"系统通知我条件就绪"的假象,可实际上你不过是在条件就绪的时候醒来,然后仍然亲自动手完成了数据复制的操作。

依然使用银行的隐喻:

柜台R:只能取款

柜台W:只能存款

read: 亲自在柜台R排队(进程睡眠) + 取款

write: 亲自在柜台W排队(进程睡眠) + 存款

select + read/write : 亲自同时在R、W两个柜台排队(进程睡眠) + (存款|取款|存款+取款)

AIO : 告诉心腹小弟要取款若干,然后忙别的事情;小弟取款完毕将其如数奉上。

UNP一书中6.2节对I/O模型的分类我觉得很合理:

1).read/write、read + NON_BLOCK、select、signal driven I/O 都属于同步I/O; 它们的共同特点是:将数据从内核空间复制到到用户空间的这个操作,是由用户空间的代码显式发起的。

2).只有AIO 属于 异步I/O;内核不露声色的将数据从内核空间复制到用户空间,然后通知进程。

-05-14 23:02 | 啸天猪

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

@啸天猪

我看了一下你的评论,我想我们之间观点最大的分歧点在于:

我的观点是同步/异步仅是消息通知的机制,至于消息到来时如何处理与这两个概念无关.

而你的观点则认为,同步/异步不仅仅包括消息通知,还包括了对消息的处理,所以select之类的通知消息的触发机制你归类为"同步",而AIO这种俘获了消息也对消息进行了处理(比如你说的将数据从内核copy到用户态)的机制才是真正的异步.

也就是说,你上面回复的这句话:

异步: 交代要做的事情,然后忙其他的事情;'别人'(内核)会充当你的跑腿,在条件就绪后将这事办成,然后通知你(callback);

事实上是我们之间对这个概念认知的最大分歧,你认为异步就是不止通知了消息,还要加上将这件事情办妥.而我认为,异步仅在于通知这个消息发生了,而具体如何处理该消息不在它关注的范围之内.

我在写上上面这段评论的时候也在思考对这个概念的理解,我还是认为我的观点是正确的,今天太晚了,改天找来UNP详细看看.

-05-14 23:54 | 那谁

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

概念真要理解了,就是一句话可以说透的。 -05-15 23:05 | Benjamin

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

@ttplay

在你下面的回复我没看

我理解的是

拿纸条和 排队的区别在于

排队的 必须自己 一直看前面是否有人 没人就是到自己了

拿纸条的就可以这样理解

坐在那里爱 干嘛干嘛 等轮到他时 柜台就给他发个消息 他收到消息就去...

他不用象排队的一样

不断检测 前面是否有人 -08-10 00:19 | 王清

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

同步异步是,一段时间里能不能做多件事情,不能,同步;能,异步。

阻塞非阻塞是,自己等待的那个步骤需要不需要自己去确认,需要则是阻塞,不需要则是非阻塞 -11-20 14:03 | wgcno7

#re: 同步/异步与阻塞/非阻塞的区别[未登录]回复更多评论

@啸天猪

大哥,你太牛逼了!! -11-27 13:18 | Squall

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

博主讲得好啊!~! -01-06 09:17 | Pigsy.Beard

#re: 同步/异步与阻塞/非阻塞的区别[未登录]回复更多评论

@那谁

select 是同步非阻塞的 -10-28 14:38 | 菜鸟

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

这些都和消息机制基本无关

同步异步是就操作发起者是否实际执行者而言的,是自己亲自去银行取钱还是让小弟帮忙解决

只有异步时才有消息的问题,小弟干完活会向你汇报,同步时你自给自己发消息啊?

阻塞与非阻塞与消息触发也没啥关系,阻塞就是不管银行排多长队等待直到取出钱,非阻塞则是发现人多可以选择不取或不在这儿取(拜托不同于发短信打电话。。。。。不能乱写无用代码)。

select/poll之类也和所谓消息机制无关,要到很多银行分别取一些钱,发现哪家银行人少就去哪家,这显然是同步的,只是需要做很多事情而不是一件。

-11-08 00:01 | yangtou

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

靠,纯粹是误人子弟

select/poll是同步的,你竟然拿来三番五次的作为异步的例子来讲

select/poll机制本来就叫多路复用I/O,或者多路同步I/O -12-02 14:57 | z_berry

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

同意@啸天猪的,select是同步阻塞的 -12-10 13:50 | unp

#re: 同步/异步与阻塞/非阻塞的区别[未登录]回复更多评论

那谁,顶你!写的真不错! -02-24 15:42 | rainfish

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

本来还比较清晰,让这位兄弟这么一说更混了,好像异步和多路I/O复用差的很远吧,扯不上什么关系吧! -03-04 22:44 | aa

#请教大家一个网络客户端设计问题回复更多评论

我写一个网络客户端sdk,我用的是select多路复用的方式,每一个socket我用一个类封装起来,用户发送一个消息就直接调用send发出去,然后数据接收到的时候会调用我类里面的OnRecvData()函数表示数据接收过来了,

但是我的程序的使用者要求要在发送消息后同步获取返回的数据,这时候最简单的办法是设置一个变量,然后轮训的查消息是否从服务器反馈回来了,但是这样这样肯定是弱智的,

那么如何给客户提供的接口是同步的呢,以下是代码的描述:

我的网络程序的内部//

//一个封装socket的类,select函数返回后会根据不同的socket句柄调用相应的类的接收数据的函数

class Client

{

void OnRecvRead()

{

recv //这里接收数据

//然后这里根据得到的消息调用不通的消息处理函数

switch()

case OnData1Recv()

case OnData2Recv()

case OnData3Recv()

}

//消息1处理函数

void OnData1Recv()

{

//接收到反馈数据1,处理数据1

}

void OnData2Recv()

{

//接收到反馈数据2,处理数据2

}

void OnData3Recv()

{

//接收到反馈数据3,处理数据3

}

SOCKET m_sock;

}

//驱动select的线程

void ThreadStartService()

{

添加多个client(ip,端口对)到FD_SET结构中

发起非阻塞连接

while(1)

{

1:select(....);//循环调用select等待某一个socket可以收消息。

2: 当等待到一个可以读数据的socket后,根据socket查找对应的Client类,然后调用Client的函数OnRecvRead();

OnRecvRead里面再分析协议,然后调用不同的函数。

}

}

给客户导出一些函数/

//启动驱动select的线程

export InitService()

{

StartThread(ThreadStartService);

}

export ProcessData1()

{

1:发数据1处理一个消息,

2:(如何实现?)这里是关键:再这个函数中返回上面“反馈数据1”。

}

export ProcessData2()

{

1:发数据2处理一个消息,

2:(如何实现?)这里是关键:再这个函数中返回上面“反馈数据2”。

}

export ProcessData3()

{

1:发数据3处理一个消息,

2:(如何实现?)这里是关键:再这个函数中返回上面“反馈数据3”。

}

客户使用我的库是先调用InitService,初始化select驱动线程。

可能在任何线程中调用ProcessData1,ProcessData2,ProcessData3,这三个函数。问题是我同步做的很不好。

抱歉写的比较啰嗦,请高人指点!

-03-08 02:12 | 张纪

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

写的很好! -03-16 17:29 | haodafeng

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

我觉得可以简单一点理解

1. 同步调用,就是这个调用结束我要知道结果,不管是成功还是失败

2. 异步调用,就是这个调用结束不需要知道结果,结果稍后通知我(回调通知)

3. 阻塞,就是调用我,调用线程可能会本挂起

4. 非阻塞,就是调用我,调用不会被挂起

-03-25 13:03 | hansonl

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

@hansonl ,精辟

-03-29 18:16 | 1212

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

@那谁

这篇文章,我同意啸天猪的概念。

同步异步我认为不是描述消息如何通知,而是两个动作的处理方式:咱俩并行?还是串行?是顺序?还是并发?如果单讲IO这一步,就不存在同步异步的问题。

比如我们一般的硬盘是同步IO,在允许读写时,cpu要等读写完成后,才能做下一件事情,就是串行;而某些SCSI卡自几有CPU, 如果它肯帮你做读写的话,我们的CPU就可以不管读写动作是否完成,而直接去做下一件事情了。类型猪说的那个父亲让儿子干活的例子。 -04-15 09:42 | 讨论

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

阿斯顿撒 -07-26 14:25 | 佛挡杀佛

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

高人帖,看帖得回帖呀!不错,醍醐灌顶 -09-01 10:47 | dotnetpig

#re: 同步/异步与阻塞/非阻塞的区别[未登录]回复更多评论

UNP6.2节,跟lz的理解有所不同的说 -10-21 09:53 | xiaok

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

楼主刚好说反了,呵呵 -03-03 13:09 | unixlover

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

楼主刚好写反了,呵呵 -03-03 13:11 | unixlover

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

楼主的描述让我学习到很多,但楼主的观点我不能完全认同。

就拿楼主的银行例子来说,

我归纳一下个人的一些观点,有不当之处希望指正。

1.同步阻塞模式:

a.通过排队等待办理业务,等待过程不做任何其他事情,由等待者自己判断是

否轮到自己。

2.同步非阻塞模式:

a.通过排队等待办理业务,等待过程中打电话、听音乐。

b.通过取号方式等待办理业务,等待过程中打电话、听音乐。

3.异步阻塞模式:

a.通过排队等待办理业务,在排队的时候“创造”一个新的人出来,让这个人

到一边呆着,不做任何事情。

b.通过取号方式等待办理业务,在等待的时候“创造”一个新的人出来,让这

个人到一边呆着,不做任何事情。

(个人认为:异步阻塞模式没有任何意义)

4.异步非阻塞模式:

a.通过排队等待办理业务,在排队的时候“创造”一个新的人出来,让这个人

到一边打电话、听音乐。

b.通过取号方式等待办理业务,在等待的时候“创造”一个新的人出来,让这

个人到一边打电话、听音乐。

所以个人认为:同步和异步的标志是看是否有新的人被“创造”出来。

而阻塞和非阻塞的标志是当同一个人在等待一个事件的时候,是

否可以继续做其他事情。 -05-30 11:30 | QQ:458885028

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

1.同步异步,是相对于你的程序框架设计

2.阻塞和非阻塞,相对于一些函数,如recv或send等

明显是不同的概念,两个不同的条件,不能混为一谈 -06-20 09:59 | QQ:343534594

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

楼主关于select的阐述有些问题,也是与啸天猪的分歧所在,但是其关于异步/同步,阻塞/非阻塞的观点很易理解也解释的很到位。

select称为“多路复用i/o”,其并不提供将数据从用户空间搬移到内核空间,或从内核空间搬移到用户空间的核心功能,因此并不能将其简单的归类于异步io、或同步io!其要完成io功能,还需要调用者从此函数成功返回后,再调用read,write,因此可将select 和 此后还需调用的read/write看做一个io整体。若select返回正值,则表示此时有设备准备好可以进行io,此时进行io,肯定不会发生阻塞,这时select+read/write,可整体看做一个同步io;至于阻塞还是非阻塞,主要要看select函数的等待时间值设定,若为null,则是阻塞式的;若为非null,则其为非阻塞的,因为其并不能保证能将数据成功写入用户空间或内核空间。select并未设置回调函数,当然不能认为具备异步io功能。 -09-26 09:58 | qq 326942298

#re: 343534594 回复更多评论

同意你的观点,但可否稍微详细点?

对于io而言,其可以分位同步io,异步io,但是这是属于程序设计的范畴,包括一系列的函数调用,如select,poll,write,read等,并不能简单的将1个函数归类于是异步的还是同步的。

而对于单个io函数,则有阻塞、非阻塞之分。 -09-26 10:18 | qq 326942298

#re:啸天猪回复更多评论

更深入的想,啸天猪的观点比较合理:

异步同步不是针对单个函数而言的,是针对程序设计而言的。

如果程序设计要求实现异步io,那楼主理解的异步仅仅是消息通知可以进行io,之后就不管io成功与否就是错误的了,与程序设计偏离了! -09-26 10:30 | qq 326942298

#re: 同步/异步与阻塞/非阻塞的区别回复更多评论

@ttplay

你的理解不对。

假设有10个业务窗口,你在1窗口排队,那你只能在这慢慢等待轮到自已,这期间你还得慢慢的往前移动(前面有人办完了),还怕别人插队,注意力分散,效率低。

而叫号等待就不一样了,10窗口都有可能叫你,你的等待时间大大缩短,等待的时候还可以看看书,玩玩游戏,效率高。 -10-27 15:11 | 直言

#re: 同步/异步与阻塞/非阻塞的区别[未登录]回复更多评论

同步和异步应该关注的是两个变化的量的对应关系,在i/o通信中“两个量”分别指什么? -03-15 20:03 | 长风

#re: 同步/异步与阻塞/非阻塞的区别[未登录]回复更多评论

表达的不是很清楚 -04-10 18:27 | 阿飞

如果觉得《同步/异步 阻塞/非阻塞区别》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。