理解同步与异步

今天看到《WIN32多线程程序设计》的同步控制时,才发现原来自己对同步和异步的概念很模糊,甚至混淆。于是GOOGLE了一下。

下面都是高人们的见解,简单明了。

------------------------------------------------------------------------------------------------------
同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式。  
异步是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式。  
 
CSDN上有讨论过:  
http://expert.csdn.net/Expert/topic/2646/2646592.xml?temp=.3842584  
http://expert.csdn.net/Expert/topic/2659/2659726.xml?temp=.1480219  
---------------------------------------------------------------  
 
举个不太恰当的例子,就像:  
SendMessage(...)  
TRACE0("just  like  send");  
 
PostMessage(...)  
TRACE0("just  like  WSASend  using  overlapped");  
 
SendMessage是调用的时候不返回,等消息响应后才执行TRACE0,这就是同步.  
PostMessage是调用后马上返回,不用消息响应就执行TRACE0,这就是异步.

答案三:

 同步和异步的区别 
 举个例子:普通B/S模式(同步)AJAX技术(异步)
同步:提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事
异步: 请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
--------------------------------------------------------------------------------------------------------------------
同步就是你叫我去吃饭,我听到了就和你去吃饭;如果没有听到,你就不停的叫,直到我告诉你听到了,才一起去吃饭。
异步就是你叫我,然后自己去吃饭,我得到消息后可能立即走,也可能等到下班才去吃饭。

所以,要我请你吃饭就用同步的方法,要请我吃饭就用异步的方法,这样你可以省钱。
--------------------------------------------------------------------------------------------------------------------
举个例子 打电话时同步 发消息是异步
-------------------------------------------------------------
同步、异步、阻塞和非阻塞的概念

在进行网络编程时,我们常常见到同步、异步、阻塞和非阻塞四种调用方式。这些方式彼此概念并不好理解。下面是我对这些术语的理解。
同步
所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。最常见的例子就是 SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函数所返回的 LRESULT值返回给调用者。
异步
异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。以CAsycSocket类为例(注意,CSocket从CAsyncSocket派生,但是起功能已经由异步转化为同步),当一个客户端通过调用 Connect函数发出一个连接请求后,调用者线程立刻可以朝下运行。当连接真正建立起来以后,socket底层会发送一个消息通知该对象。这里提到执行部件和调用者通过三种途径返回结果:状态、通知和回调。可以使用哪一种依赖于执行部件的实现,除非执行部件提供多种选择,否则不受调用者控制。如果执行部件用状态来通知,那么调用者就需要每隔一定时间检查一次,效率就很低(有些初学多线程编程的人,总喜欢用一个循环去检查某个变量的值,这其实是一种很严重的错误)。如果是使用通知的方式,效率则很高,因为执行部件几乎不需要做额外的操作。至于回调函数,其实和通知没太多区别。
阻塞
阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。例如,我们在CSocket中调用Receive函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消息。如果主窗口和调用函数在同一个线程中,除非你在特殊的界面操作函数中调用,其实主界面还是应该可以刷新。socket接收数据的另外一个函数recv则是一个阻塞调用的例子。当socket工作在阻塞模式的时候,如果没有数据的情况下调用该函数,则当前线程就会被挂起,直到有数据为止。
非阻塞
非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
对象的阻塞模式和阻塞函数调用
对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但是并不是一一对应的。阻塞对象上可以有非阻塞的调用方式,我们可以通过一定的API去轮询状态,在适当的时候调用阻塞函数,就可以避免阻塞。而对于非阻塞对象,调用特殊的函数也可以进入阻塞调用。函数select就是这样的一个例子。




调用函数: 执行操作 + 返回结果
同步涉及多个函数调用, 流程为: 执行A操作,返回A结果,执行B操作,返回B结果,执行C操作,返回C结果
异步也是涉及多个函数调用,流程可能为: 执行A操作,执行B操作,返回A结果,执行C操作,返回C结果,返回B结果
阻塞涉及一个函数调用,理解为:执行操作的调节不满足的话,线程就block在哪里,直到条件满足,或者超时,然后 返回结果,线程继续往下
非阻塞涉及一个函数调用,理解为:执行操作时不判断执行条件,直接返回,线程继续往下。
同步异步更多的是逻辑层面,而阻塞和非阻塞更多是针对单个函数。 



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

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

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

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

举个例子,比如我去银行办理业务,可能选择排队等候,也可能取一个小纸条上面有我的号码,等到排到我这一号时由柜台的人通知我轮到我去办理业务了.
前者(排队等候)就是同步等待消息,而后者(等待别人通知)就是异步等待消息.在异步消息处理中,等待消息者(在这个例子中就是等待办理业务的人)往往注册一个回调机制,在所等待的事件被触发时由触发机制(在这里是柜台的人)通过某种机制(在这里是写在小纸条上的号码)找到等待该事件的人.
而在实际的程序中,同步消息处理就好比简单的read/write操作,它们需要等待这两个操作成功才能返回;而异步处理机制就是类似于select/poll之类的多路复用IO操作,当所关注的消息被触发时,由消息触发机制通知触发对消息的处理.

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

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

可见,同步/异步与阻塞/非阻塞是两组不同的概念,它们可以共存组合,也可以参见这里:
http://www.ibm.com/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 2009-05-13 22:11 那谁 阅读(11284) 评论(25)  编辑 收藏 引用 所属分类: 网络编程 、服务器设计Linux/Unix

评论

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

bu cuo

2009-05-13 22:59 | tiny

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

我这个笨还是想不通 

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

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

不是一样啊?没什么分别呀。只不过人排列的顺序变成了号码排列的顺序。

2009-05-13 23:42 | ttplay

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

@ttplay
我的理解是:
同步的时候,不是站在你前面的人通知你,是你自己得看着你前面还有没有人。
而小纸条就不一样了,你拿了纸条就不用管了,出去溜达都可以,反正到时候有人会叫你。

2009-05-14 09:12 | Sunshine Alike

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

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

2009-05-14 09:33 | bachmozart

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

类比很恰当,确实让我又清晰了不少。
好文,作者好人。

2009-05-14 11:31 | abettor

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

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

2009-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;内核不露声色的将数据从内核空间复制到用户空间,然后通知进程。 

2009-05-14 23:02 | 啸天猪

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

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

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

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

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

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

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

2009-05-14 23:54 | 那谁

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

概念真要理解了,就是一句话可以说透的。

2009-05-15 23:05 | Benjamin

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

@ttplay 
在你下面的回复我没看 
我理解的是 
拿纸条和 排队的区别在于 
排队的 必须自己一直看前面是否有人 没人就是到自己了 
拿纸条的就可以这样理解 
坐在那里爱 干嘛干嘛等轮到他时 柜台就给他发个消息 他收到消息就去... 
他不用象排队的一样 
不断检测 前面是否有人

2009-08-10 00:19 | 王清

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

同步异步是,一段时间里能不能做多件事情,不能,同步;能,异步。
阻塞非阻塞是,自己等待的那个步骤需要不需要自己去确认,需要则是阻塞,不需要则是非阻塞

2009-11-20 14:03 | wgcno7

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

@啸天猪 

大哥,你太牛逼了!!

2009-11-27 13:18 | Squall

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

博主讲得好啊!~!

2010-01-06 09:17 | Pigsy.Beard

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

@那谁
select 是同步非阻塞的

2010-10-28 14:38 | 菜鸟

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

这些都和消息机制基本无关 
同步异步是就操作发起者是否实际执行者而言的,是自己亲自去银行取钱还是让小弟帮忙解决 

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

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

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

2010-11-08 00:01 | yangtou

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

靠,纯粹是误人子弟
select/poll是同步的,你竟然拿来三番五次的作为异步的例子来讲
select/poll机制本来就叫多路复用I/O,或者多路同步I/O

2010-12-02 14:57 | z_berry

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

同意@啸天猪的,select是同步阻塞的


  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值