什么是同步與異步跌造、阻塞與非阻塞
引用知乎 怎樣理解阻塞非阻塞與同步異步的區(qū)別定罢? 上面的一個回答,很生動的說明了同步異步淳玩,阻塞非阻塞之間的區(qū)別聯(lián)系:
老張愛喝茶直撤,廢話不說,煮開水蜕着。
出場人物:老張谋竖,水壺兩把(普通水壺,簡稱水壺承匣;會響的水壺蓖乘,簡稱響水壺)。
1 老張把水壺放到火上韧骗,立等水開嘉抒。(同步阻塞)
老張覺得自己有點傻
2 老張把水壺放到火上,去客廳看電視袍暴,時不時去廚房看看水開沒有些侍。(同步非阻塞)
老張還是覺得自己有點傻,于是變高端了政模,買了把會響笛的那種水壺娩梨。水開之后,能大聲發(fā)出嘀~~~~的噪音览徒。
3 老張把響水壺放到火上狈定,立等水開。(異步阻塞)
老張覺得這樣傻等意義不大
4 老張把響水壺放到火上习蓬,去客廳看電視纽什,水壺響之前不再去看它了,響了再去拿壺躲叼。(異步非阻塞)
老張覺得自己聰明了芦缰。
所謂同步異步,只是對于水壺而言枫慷。普通水壺让蕾,同步浪规;響水壺,異步探孝。雖然都能干活笋婿,但響水壺可以在自己完工之后,提示老張水開了顿颅。這是普通水壺所不能及的缸濒。同步只能讓調(diào)用者去輪詢自己(情況2中),造成老張效率的低下粱腻。
所謂阻塞非阻塞庇配,僅僅對于老張而言。立等的老張绍些,阻塞捞慌;看電視的老張,非阻塞柬批。情況1和情況3中老張就是阻塞的啸澡,媳婦喊他都不知道。雖然3中響水壺是異步的萝快,可對于立等的老張沒有太大的意義锻霎。所以一般異步是配合非阻塞使用的,這樣才能發(fā)揮異步的效用揪漩。
看上面的例子旋恼,我們再來關注Linux網(wǎng)絡IO模型,然后結(jié)合這個例子去理解奄容。
Linux網(wǎng)絡IO模型
Unix提供了五種IO模式冰更,分別是:
阻塞IO
非阻塞IO
IO復用
信號驅(qū)動IO
異步IO
在之前的學習中我們也了解了從用戶進程到底層硬件執(zhí)行IO的過程,以read為例:
數(shù)據(jù)需要從硬件設備拷貝到內(nèi)核空間的緩沖區(qū)昂勒,然后從內(nèi)核緩沖區(qū)拷貝到用戶進程空間蜀细。
我們把數(shù)據(jù)需要從硬件設備拷貝到內(nèi)核空間的緩沖區(qū)這個過程類比為燒水,從內(nèi)核緩沖區(qū)拷貝到用戶進程空間這個過程類比為用燒好的水泡茶戈盈。
阻塞IO
阻塞IO是最常用的IO模型奠衔,我們在java中調(diào)用傳統(tǒng)BIO(InputStream、OutpuytStream)的讀寫方法都是這種IO模型塘娶。
觀察上圖归斤,在進程空間中調(diào)用recvfrom,其系統(tǒng)調(diào)用直到數(shù)據(jù)從硬件設備拷貝到內(nèi)核緩沖區(qū)并且從內(nèi)核拷貝到用戶進程空間時才會返回刁岸,在此期間一直是阻塞的脏里,進程在從調(diào)用recvfrom到他返回這段時間一直都是阻塞的,故稱為阻塞IO虹曙。
阻塞IO對應了我們上面提到的同步阻塞迫横。在這種IO模式下整個過程相當于使用不會響的普通水壺燒水番舆,并且老張一直在旁邊盯著,干不了其他事矾踱。水燒好后老張再去泡茶恨狈。整個過程是同步阻塞的。
在阻塞IO模式下介返,在同一個線程當中拴事,我們對于多個連接沃斤,只能依次處理:
while true {
for i in stream[] {
//可能會阻塞很長時間
read until available
}
}
非阻塞IO
用戶進程發(fā)起一個recvfrom調(diào)用的時候圣蝎,如果內(nèi)核緩沖區(qū)的數(shù)據(jù)還沒有準備好(沒有完全從硬件拷貝到內(nèi)核),那么他不會阻塞用戶進程衡瓶,而是立刻返回一個error徘公。用戶發(fā)起一個recvfrom操作之后,不需要等待哮针,而是馬上會得到一個結(jié)果关面,用戶可以判斷這個結(jié)果,如果是一個error十厢,表示數(shù)據(jù)還沒有準備好等太,于是可以再次發(fā)起recvfrom操作,一旦內(nèi)核數(shù)據(jù)準備好了蛮放,就可以把數(shù)據(jù)拷貝到用戶進程空間缩抡,然后返回。
這種IO模型稱之為非阻塞IO包颁,整個過程可以類比為:在這種IO模式下調(diào)用recvfrom相當于使用不會響的普通水壺燒水柳恐,老張時不時跑到廚房看看水燒開了沒(這個過程是同步非阻塞的)栗恩,如果水燒開了,他就用燒開的水泡茶(相當于從內(nèi)核copy數(shù)據(jù)到用戶空間這一段,這個過程其實是同步阻塞的)
在非阻塞IO模式下歼跟,我們發(fā)現(xiàn)可以在一個線程中處理多個連接了:
// 忙輪詢
while true {
for i in stream[]; {
// 如果數(shù)據(jù)沒有準備好,就立即返回愧驱,處理下一個流
read until unavailable
}
}
我們只要不停的把所有流從頭到尾問一遍派桩,又從頭開始。這樣就可以處理多個流了贵少,但這樣的做法顯然不好呵俏,因為如果所有的流都沒有數(shù)據(jù),那么只會白白浪費CPU春瞬。
為了避免CPU空轉(zhuǎn)柴信,可以引進了一個代理: select或poll(兩者本質(zhì)上相同)
IO復用
Linux 提供了select/poll,進程將一個或多個fd傳遞給select或poll系統(tǒng)調(diào)用宽气,并且阻塞在select或poll方法上随常。同時潜沦,kernel會偵測所有select負責的fd是否處于就緒狀態(tài),如果有任何一個fd就緒绪氛,select或poll就會返回唆鸡,這個時候用戶進程再調(diào)用recvfrom,將數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到用戶進程空間枣察。
這個圖和blocking IO的圖有些相似争占,但是還有一些區(qū)別。因為這里需要使用兩個system call (select 和 recvfrom)序目,而blocking IO只調(diào)用了一個system call (recvfrom)臂痕。但是,用select的優(yōu)勢在于它可以同時處理多個connection猿涨。
while true {
// 在select上阻塞
select(streams[])
// 無差別輪詢
for i in streams[] {
read until unavailable
}
}
于是握童,如果沒有I/O事件產(chǎn)生,我們的程序就會阻塞在select處叛赚。但是依然有個問題澡绩,我們從select那里僅僅知道了,有I/O事件發(fā)生了俺附,但卻并不知道是那幾個流(可能有一個肥卡,多個,甚至全部)事镣,我們只能無差別輪詢所有流步鉴,找出能讀出數(shù)據(jù),或者寫入數(shù)據(jù)的流蛮浑,對他們進行操作唠叛。使用select,我們有O(n)的無差別輪詢復雜度沮稚,同時處理的流越多艺沼,每一次無差別輪詢時間就越長。
Linux還提供了一個epoll系統(tǒng)調(diào)用蕴掏,不同于忙輪詢和無差別輪詢障般,epoll之會把哪個流發(fā)生了怎樣的I/O事件通知我們。此時我們對這些流的操作都是有意義的(復雜度降低到了O(1))盛杰。
// 事先調(diào)用epoll_ctl注冊感興趣的事件到epollfd
while true {
// 返回觸發(fā)注冊事件的流
active_stream[] = epoll_wait(epollfd)
// 無須遍歷所有的流
for i in active_stream[] {
read or write till
}
}
信號驅(qū)動IO
首先開啟套接口信號驅(qū)動IO功能挽荡,并通過系統(tǒng)調(diào)用sigaction執(zhí)行一個信號處理函數(shù),此系統(tǒng)調(diào)用立即返回即供。當數(shù)據(jù)準備就緒時定拟,就為該進程生成一個sigio信號,通過信號回調(diào)通知進程逗嫡。進程調(diào)用recvfrom讀取數(shù)據(jù)青自,將數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到用戶進程空間株依。
上面的過程可以類比為:老張使用會響的水壺燒水,然后就去客廳看電視了延窜。水燒好后水壺響起來(這個過程是異步非阻塞的)恋腕,老張再來廚房用燒好的水泡茶(這個過程是同步阻塞的)。
異步IO
用戶進程發(fā)起recvfrom操作之后逆瑞,立刻就可以開始去做其它的事荠藤。而另一方面,從kernel的角度获高,當它收到一個asynchronous read之后哈肖,首先它會立刻返回,所以不會對用戶進程產(chǎn)生任何block谋减。然后牡彻,kernel會等待數(shù)據(jù)準備完成扫沼,然后將數(shù)據(jù)拷貝到用戶內(nèi)存出爹,當這一切都完成之后,kernel會給用戶進程發(fā)送一個signal缎除,告訴它read操作完成了严就。
這種IO模式與信號驅(qū)動IO的區(qū)別在于:信號驅(qū)動IO由內(nèi)核通知我們什么時候可以開始一個IO操作,異步IO則由內(nèi)核告訴我們IO操作何時完成器罐。
異步IO模式可以類比為:在這種IO模式下整個過程相當于使用會響的水壺燒水梢为,并且,這個水壺更加智能轰坊,水燒好后可以自動泡茶铸董,然后發(fā)出聲響通知老張。老張把水放到火上就去客廳看電視了肴沫,水燒好并且茶葉泡好之后粟害,水壺發(fā)出聲響通知老張。
參考
Linux IO模式及 select颤芬、poll悲幅、epoll詳解
《Netty權(quán)威指南》 電子工業(yè)出版社