您的位置:首页 > 编程语言

并发编程基础概念(一) IO-同步,异步,阻塞,非阻塞

2015-10-07 15:03 676 查看
同步阻塞IO:



    在 这个模型中,应用程序(application)为了执行这个read操作,会调用相应的一个system call,将系统控制权交给kernel,然后就进行等待(这其实就是被阻塞了)。kernel开始执行这个system call,执行完毕后会向应用程序返回响应,应用程序得到响应后,就不再阻塞,并进行后面的工作。 

 

   举一个浅显的例子,就好比你去一个银行柜台存钱。首先,你会将存钱的单子填好,然后交给柜员。这里,你就好比是application,单子就是调用的 system call,柜员就是kernel。提交好单子后,你就坐在柜台前等,相当于开始进行等待。柜员办好以后会给你一个回执,表示办好了,这就是 response。然后你就可以拿着回执干其它的事了。注意,这个时候,如果你办完之后马上去查账,存的钱已经打到你的账户上了。后面你会发现, 这点很重要。 

 

同步非阻塞IO:  

  



   在linux下,应用程序可以通过设置文件描述符的属性O_NONBLOCK,I/O操作可以立即返回,但是并不保证I/O操作成功。

   也 就是说,当应用程序设置了O_NONBLOCK之后,执行write操作,调用相应的system call,这个system call会从内核中立即返回。但是在这个返回的时间点,数据可能还没有被真正的写入到指定的地方。也就是说,kernel只是很快的返回了这个 system call(这样,应用程序不会被这个IO操作blocking),但是这个system call具体要执行的事情(写数据)可能并没有完成。而对于应用程序,虽然这个IO操作很快就返回了,但是它并不知道这个IO操作是否真的成功了,如果想 知道,需要应用程序主动地去问kernel。

   这次不是去银行存钱,而是去银行汇款。同样的,你也需要填写汇款单然后交给柜员,柜员进行一 些简单的手续处理就能够给你回执。但是,你拿到回执并不意味着钱已经打到了对方的账上。事实上,一般汇款的周期大概是24个小时,如果你要以存钱的模式来 汇款的话,意味着你需要在银行等24个小时,这显然是不现实的。所以,同步非阻塞IO在实际生活中也是有它的意义的。

 

异步阻塞IO:

 



    和 之前一样,应用程序要执行read操作,因此调用一个system call,这个system call被传递给了kernel。但在应用程序这边,它调用system call之后,并不等待kernel返回response,这一点是和前面两种机制不一样的地方。这也是为什么它被称为异步的原因。但是为什么称其为阻塞 呢?这是因为虽然应用程序是一个异步的方式,但是select()函数会将应用程序阻塞住,一直等到这个system call有结果返回了,再通知应用程序。也就是说,“在这种模型中,配置的是非阻塞
I/O,然后使用阻塞 select 系统调用来确定一个 I/O 描述符何时有操作。”

所以,从IO操作的实际效果来看,异步阻塞IO和第一种同步阻塞IO是一样的,应用程序都是一直等到IO操作成功之后(数据已经被写入或者读取),才开始进行下面的工作。异步阻塞IO的好处在于一个select函数可以为多个描述符提供通知,提高了并发性。

    关 于提高并发性这点,我们还以银行为例说明。比如说一个银行柜台,现在有10个人想存钱。按照现在银行的做法,一个个排队。第一个人先填存款单,然后提交, 然后柜员处理,然后给回执,成功后再轮到下一个人。大家应该都在银行排过对,这样的流程是很痛苦的。如果按照异步阻塞的机制,10个人都填好存款单,然后 都提交给柜台,提交完之后所有的10个人就在银行大厅等待。这时候会专门有个人,他会了解存款单处理的情况,一旦有存款单处理完毕,他会将回执交给相应的 正在大厅等待的人,这个拿到回执的人就可以去干其他的事情了。而前面提到的这个专人,就对应于select函数。

异步非阻塞IO: 



    如 图所示,应用程序提交read请求的system call,然后,kernel开始处理相应的IO操作,而同时,应用程序并不等kernel返回响应,就会开始执行其他的处理操作(应用程序没有被IO操 作所阻塞)。当kernel执行完毕,返回read的响应,就会产生一个信号或执行一个基于线程的回调函数来完成这次 I/O 处理过程。

   比如银行存钱。现在某银行新开通了一项存钱业务。用户之需要将存款单交给柜台,然后无需等待就可以离开了。柜台办好以后会给用户发送一条短信,告知交易成功。这样用户不需要在柜台前进行长时间的等待,同时,也能够得到确切的消息知道交易完成。 

所谓的同步和异步,在这里指的是application和kernel之间的交互方式。如果application不需要等待 kernel的回应,那么它就是异步的。如果application提交完IO请求后,需要等待“回执”,那么它就是同步的。

而阻塞和非阻塞,指的是application是否等待IO操作的完成。如果application必须等到IO操作实际完成以后再执行下面的操作,那么它是阻塞的。反之,如果不等待IO操作的完成就开始执行其它操作,那么它是非阻塞的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: