Creative Commons License
本Blog采用 知识共享署名-非商业性使用-禁止演绎 3.0 Unported许可协议 进行许可。 —— Fox <游戏人生>

游戏人生

游戏人生 != ( 人生 == 游戏 )
站点迁移至:http://www.yulefox.com。请订阅本博的朋友将RSS修改为http://feeds.feedburner.com/yulefox
posts - 62, comments - 508, trackbacks - 0, articles - 7

再辨同步/异步与阻塞/非阻塞

Posted on 2008-09-11 01:11 Fox 阅读(4854) 评论(12)  编辑 收藏 引用 所属分类: T技术碎语

网络编程学习和实践的过程中,同步(synchronous)/异步(asynchronous)阻塞(blocking)/非阻塞(non-blocking)总是会迷惑很多人。依然记得我半年之前在记述IOCP时,一句不经意的“非阻塞I/O则是致力于提供高效的异步I/O”便引来一番口水论争。

今天在查一些资料的时候,看到关于这几个词的论辩竟不是一般的多,细细想来,这个问题似乎也确实有解释的必要,不在于争论对错,而在于辨明是非。

讨论之前,先限定讨论的范围:此处之同步/异步仅限于I/O操作,与OS所讨论的进程/线程中的其他同步/异步没有直接关系;讨论的内容是:两对相似的术语之间的区别到底有多大

  • 非常大:

Douglas C. Schmidt在《C++网络编程》中这样说到:

They are very different, as follows:

AIO is "asynchronous I/O", i.e., the operation is invoked asynchronously and control returns to the client while the OS kernel processes the I/O request.  When the operation completes there is some mechanism for the client to retrieve the results.

Non-blocking I/O tries an operation (such as a read() or write()) and if it the operation would block (e.g., due to flow control on a TCP connection or due to lack of data in a socket), the call returns -1 and sets errno to EWOULDBLOCK.

翻译如下:

:例如,操作被异步调用时,控制权交给客户端,I/O操作请求则交由操作系统内核处理,当操作完成后,通过某种机制将结果通知客户端。

非阻塞I/O:尝试调用某操作,如果操作被阻塞,则调用返回-1并置错误值为EWOULDBLOCK。

从这两段“very different”的解释来看,我的感觉是并没有指出二者的区别,因为我们无法确定所谓AIO是如何处理的,如果AIO直接“调用返回-1并置错误值为EWOULDBLOCK”,实现“控制权交给客户端”,似乎并无任何不妥。况且,对于非阻塞I/O,我们也需要“当操作完成后,通过某种机制将结果通知客户端”这样的处理。

  • 无差别:

而在Wikipedia上则直接等同二者:Asynchronous I/O, or non-blocking I/O, is a form of input/output processing that permits other processing to continue before the transmission has finished.

当然,对于recv和send,我们一般会说他们是阻塞起的,而不会说他们是同步起的,但这显然不是二者的区别,因为我们都知道,阻塞的原因正是等待同步结果的返回

因此,二者的区别在于,阻塞/非阻塞是表现,同步/异步是原因,我们说某某操作是阻塞起的,或者某某线程是阻塞起的,是因为在等待操作结果的同步返回;我们说某某操作是非阻塞的,是因为操作结果会通过异步方式返回。

讨论到这儿,再咬文嚼字的争辩下去似乎已经没有任何实际意义。

------------------------------------------------------------

PS:纠结一些必要的概念是为了加深理解,太过纠结了反倒会滞塞理解。我之前对于其概念也并非特别清楚,所以才会再续一篇特意言明,也算弥补一下自己的过失。

Feedback

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

2008-09-11 13:17 by Alex
TKS,加强理解

# re: 再辨同步/异步与阻塞/非阻塞  回复  更多评论   

2008-09-11 14:29 by k120

SELECT 是用于检查SOCKET上有无可读/可写数据,是非阻塞的,但是是同步的。

# re: 再辨同步/异步与阻塞/非阻塞  回复  更多评论   

2008-09-11 14:47 by Fox
select在等待时间timeout>0的情况下是阻塞的,这时才有你所说的同步。
如果timeout==0,才是非阻塞的,有无数据都是立即返回,自然没有同步问题。

# re: 再辨同步/异步与阻塞/非阻塞  回复  更多评论   

2008-09-11 17:59 by LOGOS
如果你是指将控制权交给客户端,那么异步和非阻塞没什么差别
但是非阻塞的东西不一定会给你回调通知,而异步则一定会
我觉得这两个词不是用来描述同样的事情的

# re: 再辨同步/异步与阻塞/非阻塞  回复  更多评论   

2008-09-12 09:24 by Fox
@LOGOS
你说的对,但如果说“非阻塞的东西不一定会给你回调通知”,那么这时候在所阻塞和非阻塞也就没有意义了,既然不需要回调/事件通知或其他任何形式的回馈,也就没有阻塞的意义了,就是普通调用,无所谓阻塞不阻塞了,对吧?

# re: 再辨同步/异步与阻塞/非阻塞  回复  更多评论   

2008-09-23 15:20 by sl
I don't know what you are talking about. Douglas had a very clear description about it: they are different.

How can you explain that a nonblocking reading from a file descriptor will return immediately, but there is no async processing if without a proper configuring. Fox, it does make sense when you wanna polling data from the descriptor.

Hi, buddy, Do some experiments, use fcntl() and some multi-threads or multi-proess tech. you will understand what differents are there.


to specify nonblocking I/O
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Use the F_SETFL command with fcntl and enable the O_NONBLOCK file flag.


to specify AIO:
~~~~~~~~~~~~~~~~
Use the F_SETFL command with fcntl and enable the O_ASYNC file flag.


To receive the SIGIO signal, we need to perform three steps.

1. Establish a signal handler for SIGIO, by calling either signal or sigaction.
2. Set the process ID or process group ID to receive the signal for the descriptor, by calling fcntl with a command of F_SETOWN (Section 3.14).
3. Enable asynchronous I/O on the descriptor by calling fcntl with a command of F_SETFL to set the O_ASYNC file status flag (Figure 3.9).

# re: 再辨同步/异步与阻塞/非阻塞  回复  更多评论   

2008-09-23 16:12 by Fox
@sl
我在上面提到“我们说某某操作是非阻塞的,是因为操作结果会通过异步方式返回”,Douglas说的是there is no async processing if without a proper configuring,意思是:

非阻塞之后可以不做异步处理。

但非阻塞和异步仍然是紧密联系而非区别非常大。
Douglas这本书我手头现在没有:(,翻了一下adv. pro. in UNIX,没有看到详细说明:(。

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

2008-09-23 16:45 by Xw.Y
作为一个不懂网络编程,仅看了此片博文和之后评论的人,一下是我的理解:

1. AIO是对于某个操作的定义,我们可以说某个函数是同步操作,或者某个函数是异步操作。
2. non-blocking是对于某个操作结果的定义,我们可以说某一个函数(比如read)是non-blocking的,如果这个函数立即返回并且得到正常调用结果。对于同样一个函数如果返回了一个block的标记,那么它就是blocking的调用。

在博主的引用和sl评论的引用中似乎都很肯定的说,
”AIO和non-blocking是完全同的两件事!“

哇哈哈,大家来砸我吧~
(此人不懂网络编程)

# re: 再辨同步/异步与阻塞/非阻塞  回复  更多评论   

2008-12-08 14:50 by yqf
我认为,首先要明白这些概念所描述的对象。在此可以理解为应用进程、内核进程以及IO,异步/同步描述的是前两个在不同情况下的关系,non-blocking/blocking描述的是后两个之间的不同处理,可以做不同组合
非阻塞之后可以不做异步处理,非常有道理,这实际上和同步非阻塞处理事物没有区别

# re: 再辨同步/异步与阻塞/非阻塞  回复  更多评论   

2009-01-01 16:27 by 叶先生
“阻塞/非阻塞是表现,同步/异步是原因”,这句总结得非常好。我同意
“我们说某某操作是非阻塞的,是因为操作结果会通过异步方式返回”这句说得有点片面。因为存在另一种情况:如果某个函数表现为非阻塞,但他却可能是同步的。“k120”回复中有提到这种情况,下面我也会举例子。

一个函数要么是同步要么是异步的,但是同步函数会引发两种不同的表现。1:阻塞,在从此函数返回之前,当前线程不能响应其他消息。2:非阻塞,虽然还没有从函数中返回,但是却可以响应其他消息。

但是异步函数却只有一种表现,那就是非阻塞。

以下两个函数都是同步的,即是不做完事情不出返回。但却是两种表现,test1在没有返回之前,界面是不会响应消息的,这就叫阻塞,你试着拖动一下窗体,会没有反应,像死机一样的。test2也是同步的,不做完事不返回的,但是你却可以拖动窗体,窗体会重绘,这叫非阻塞。

C#代码:
做一个C# WinForms的工程,在两个按钮事件中分别调用下面两个不同的函数。
void test1()//同步函数,会阻塞线程
{
for(long i=0;i<99999999999;i++)
{
//什么也不做,i值到了999999999之后才返回
}
}
----------------------------------------
void test2()//同步函数,不会阻塞线程
{
for(long i=0;i<99999999999;i++)
{
Application.DoEvent();//C++程序员说这是“消息泵”
//和上面那函数一样,只是多了这一句而已。这句有魔术作用。有“中断”的效
果,会检查消息队列有无要处理的消息,有就会跑去执行队列中的消息响应函
数,执行完后又跑回这里来。
}
}

异步函数我就一下子举不出例子了,异步就是即时返回,执行结果通过回调,消息之类的去通知调用者,因为是即时返回,想阻塞都阻塞不了。
理解这几个词还是从他们的词性,所描述的对象出发。
这是我个人的理解,如有错误,敬请具体地指错在哪句。

# re: 再辨同步/异步与阻塞/非阻塞  回复  更多评论   

2009-01-02 13:38 by Fox
@叶先生
你给的第一个的例子并不太合适,阻塞实际是指因继续执行的条件不满足(事件未到达)而挂起等待,test1实际并未挂起,只是一直在执行一个空循环而已。
test2只是 多了一个DoEvent,如果讨论同步还是异步,实际要视DoEvent而定,若DoEvent像你所说,那可以作为异步看待,如果DoEvent阻塞等待事件到来,则成了同步,但这都与你给的循环没有关系。

至于你说test1会“卡死”,那是因为单线程的话,需要不停的执行循环,但没有阻塞,因为循环一直在跑:)

# re: 再辨同步/异步与阻塞/非阻塞  回复  更多评论   

2012-04-12 17:26 by 孙永杰
"没有从函数中返回,但是却可以响应其他消息"不能够吧?响应也是其它线程响应的

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理