IO - 同步,異步,阻塞,,非阻塞 March 11th, 2010
同步阻塞IO
在這個(gè)模型中,,應(yīng)用程序(application)為了執(zhí)行這個(gè)read操作,會(huì)調(diào)用相應(yīng)的一個(gè)system call,,將系統(tǒng)控制權(quán)交給kernel,,然后就進(jìn)行等待(這其實(shí)就是被阻塞了)。kernel開始執(zhí)行這個(gè)system call,,執(zhí)行完畢后會(huì)向應(yīng)用程序返回響應(yīng),,應(yīng)用程序得到響應(yīng)后,就不再阻塞,,并進(jìn)行后面的工作,。
例如,“在調(diào)用 read 系統(tǒng)調(diào)用時(shí),,應(yīng)用程序會(huì)阻塞并對內(nèi)核進(jìn)行上下文切換,。然后會(huì)觸發(fā)讀操作,當(dāng)響應(yīng)返回時(shí)(從我們正在從中讀取的設(shè)備中返回),,數(shù)據(jù)就被移動(dòng)到用戶空間的緩沖區(qū)中,。然后應(yīng)用程序就會(huì)解除阻塞(read 調(diào)用返回)。”舉一個(gè)淺顯的例子,,就好比你去一個(gè)銀行柜臺存錢,。首先,你會(huì)將存錢的單子填好,,然后交給柜員,。這里,你就好比是application,,單子就是調(diào)用的 system call,,柜員就是kernel。提交好單子后,,你就坐在柜臺前等,,相當(dāng)于開始進(jìn)行等待。柜員辦好以后會(huì)給你一個(gè)回執(zhí),,表示辦好了,這就是 response,。然后你就可以拿著回執(zhí)干其它的事了,。注意,這個(gè)時(shí)候,,如果你辦完之后馬上去查賬,,存的錢已經(jīng)打到你的賬戶上了。后面你會(huì)發(fā)現(xiàn),這點(diǎn)很重要,。
同步非阻塞IO
在linux下,,應(yīng)用程序可以通過設(shè)置文件描述符的屬性O(shè)_NONBLOCK,I/O操作可以立即返回,,但是并不保證I/O操作成功,。也就是說,當(dāng)應(yīng)用程序設(shè)置了O_NONBLOCK之后,,執(zhí)行write操作,,調(diào)用相應(yīng)的system call,這個(gè)system call會(huì)從內(nèi)核中立即返回,。但是在這個(gè)返回的時(shí)間點(diǎn),,數(shù)據(jù)可能還沒有被真正的寫入到指定的地方。也就是說,,kernel只是很快的返回了這個(gè) system call(這樣,,應(yīng)用程序不會(huì)被這個(gè)IO操作blocking),但是這個(gè)system call具體要執(zhí)行的事情(寫數(shù)據(jù))可能并沒有完成,。而對于應(yīng)用程序,,雖然這個(gè)IO操作很快就返回了,但是它并不知道這個(gè)IO操作是否真的成功了,,如果想知道,,需要應(yīng)用程序主動(dòng)地去問kernel。這次不是去銀行存錢,,而是去銀行匯款,。同樣的,你也需要填寫匯款單然后交給柜員,,柜員進(jìn)行一些簡單的手續(xù)處理就能夠給你回執(zhí),。但是,你拿到回執(zhí)并不意味著錢已經(jīng)打到了對方的賬上,。事實(shí)上,,一般匯款的周期大概是24個(gè)小時(shí),如果你要以存錢的模式來匯款的話,,意味著你需要在銀行等24個(gè)小時(shí),,這顯然是不現(xiàn)實(shí)的。所以,,同步非阻塞IO在實(shí)際生活中也是有它的意義的,。
異步阻塞IO
和之前一樣,應(yīng)用程序要執(zhí)行read操作,,因此調(diào)用一個(gè)system call,,這個(gè)system call被傳遞給了kernel。但在應(yīng)用程序這邊,它調(diào)用system call之后,,并不等待kernel返回response,,這一點(diǎn)是和前面兩種機(jī)制不一樣的地方。這也是為什么它被稱為異步的原因,。但是為什么稱其為阻塞呢,?這是因?yàn)殡m然應(yīng)用程序是一個(gè)異步的方式,但是select()函數(shù)會(huì)將應(yīng)用程序阻塞住,,一直等到這個(gè)system call有結(jié)果返回了,,再通知應(yīng)用程序。也就是說,,“在這種模型中,,配置的是非阻塞 I/O,然后使用阻塞 select 系統(tǒng)調(diào)用來確定一個(gè) I/O 描述符何時(shí)有操作,。”所以,,從IO操作的實(shí)際效果來看,異步阻塞IO和第一種同步阻塞IO是一樣的,,應(yīng)用程序都是一直等到IO操作成功之后(數(shù)據(jù)已經(jīng)被寫入或者讀?。砰_始進(jìn)行下面的工作,。異步阻塞IO的好處在于一個(gè)select函數(shù)可以為多個(gè)描述符提供通知,,提高了并發(fā)性。關(guān)于提高并發(fā)性這點(diǎn),,我們還以銀行為例說明,。比如說一個(gè)銀行柜臺,現(xiàn)在有10個(gè)人想存錢,。按照現(xiàn)在銀行的做法,,一個(gè)個(gè)排隊(duì)。第一個(gè)人先填存款單,,然后提交,,然后柜員處理,然后給回執(zhí),,成功后再輪到下一個(gè)人,。大家應(yīng)該都在銀行排過對,這樣的流程是很痛苦的,。如果按照異步阻塞的機(jī)制,,10個(gè)人都填好存款單,然后都提交給柜臺,,提交完之后所有的10個(gè)人就在銀行大廳等待。這時(shí)候會(huì)專門有個(gè)人,他會(huì)了解存款單處理的情況,,一旦有存款單處理完畢,,他會(huì)將回執(zhí)交給相應(yīng)的正在大廳等待的人,這個(gè)拿到回執(zhí)的人就可以去干其他的事情了,。而前面提到的這個(gè)專人,,就對應(yīng)于select函數(shù)。
異步非阻塞IO
如圖所示,,應(yīng)用程序提交read請求的system call,,然后,kernel開始處理相應(yīng)的IO操作,,而同時(shí),,應(yīng)用程序并不等kernel返回響應(yīng),就會(huì)開始執(zhí)行其他的處理操作(應(yīng)用程序沒有被IO操作所阻塞),。當(dāng)kernel執(zhí)行完畢,,返回read的響應(yīng),就會(huì)產(chǎn)生一個(gè)信號或執(zhí)行一個(gè)基于線程的回調(diào)函數(shù)來完成這次 I/O 處理過程,。比如銀行存錢?,F(xiàn)在某銀行新開通了一項(xiàng)存錢業(yè)務(wù)。用戶之需要將存款單交給柜臺,,然后無需等待就可以離開了,。柜臺辦好以后會(huì)給用戶發(fā)送一條短信,告知交易成功,。這樣用戶不需要在柜臺前進(jìn)行長時(shí)間的等待,,同時(shí),也能夠得到確切的消息知道交易完成,。從前面的介紹中可以看出,,所謂的同步和異步,在這里指的是application和kernel之間的交互方式,。如果application不需要等待 kernel的回應(yīng),,那么它就是異步的。如果application提交完IO請求后,,需要等待“回執(zhí)”,,那么它就是同步的。而阻塞和非阻塞,,指的是application是否等待IO操作的完成,。如果application必須等到IO操作實(shí)際完成以后再執(zhí)行下面的操作,那么它是阻塞的,。反之,,如果不等待IO操作的完成就開始執(zhí)行其它操作,,那么它是非阻塞的。 |
|