I/O模型
從策劃到設計制作,每一步都追求做到細膩,制作可持續(xù)發(fā)展的企業(yè)網(wǎng)站。為客戶提供網(wǎng)站設計制作、做網(wǎng)站、網(wǎng)站策劃、網(wǎng)頁設計、域名與空間、虛擬主機、網(wǎng)絡營銷、VI設計、 網(wǎng)站改版、漏洞修補等服務。為客戶提供更好的一站式互聯(lián)網(wǎng)解決方案,以客戶的口碑塑造優(yōu)易品牌,攜手廣大客戶,共同發(fā)展進步。
Unix下共有五種I/O模型:
1>:阻塞I/O
2>:非阻塞I/O
3>:I/O多路復用
4>:信號驅動I/O
5>:異步I/O
其中前四種是同步I/O模型,只有第五種是異步的。
同步與異步:
這里的同步和兩個實體之間通信中的同步的概念是不一樣的,這里的同步是指關于這個I/O中的一系列動作都需要自己來完成,無論你是原地等待事件的發(fā)生(阻塞)還是當某個事件已經準備好的時候你去完成后面的的動作(非阻塞)都屬于同步。
異步,它是指是調用另一個執(zhí)行者去完成,當執(zhí)行者發(fā)現(xiàn)要處理的時間后調用你,你再完成這件事情,執(zhí)行的過程和你的動作是不牽扯的。
阻塞與非阻塞:
阻塞是指,等待某個事件的發(fā)生,如果它沒有發(fā)生則一直等待下去直到事件發(fā)生為止。
非阻塞,不需要死死的等待,當它有返回的時候再去處理。
1>阻塞I/O
使用的I/O函數(shù),導致程序阻塞,等待數(shù)據(jù),如果數(shù)據(jù)沒有準備好則一直等待。
例如我們使用的阻塞式的socket創(chuàng)建套接字的時候,調用accept/recvfrom/connect...等都會是阻塞式的等待連接,請求或者數(shù)據(jù)的到來
阻塞式的函數(shù)實現(xiàn)起來很簡單,但它有很多的問題,首先作為一個網(wǎng)絡的服務器,阻塞式的等待會浪費大量的資源和時間,當服務器調用函數(shù)sendto給遠端的一個客戶端發(fā)送數(shù)據(jù)時,這時候不做其他的事情那么往后的動作都堵塞在后面,這樣顯然是不合適的,解決這種問題的方法往往是創(chuàng)建一個進程或者線程去解決這件事,因為進程的開銷遠遠地大于線程的開銷,所以使用多線程的方法解決是很行得通的。
阻塞式的I/O的好處就是它非常的穩(wěn)定,他能保證連接保證接受和發(fā)送數(shù)據(jù)的確定性,這是大多大的互聯(lián)網(wǎng)公司使用多線程的原因,并且使用線程池也會大大增加線程開啟的效率。
2>非阻塞式I/O
調用socket函數(shù)并將其設置為非阻塞模式,設置方式,linux下調用fcntl()函數(shù)。
非阻塞方式下,當前執(zhí)行流不再以睡眠的方式來等待請求或者數(shù)據(jù)的到來,而采用輪詢的方式,這種方式的運作流程是這樣的,每隔一個時間段便返回一次,如果有數(shù)據(jù)到來則返回,如果沒有,則返回一個錯誤碼WSAEWOULDBLOCK,我們需要不斷的用循環(huán)來等待數(shù)據(jù)的成功返回,這個過程往往會占用大量的CPU。
非阻塞的缺點,雖然他不用再使等待太僵硬,但它不可避免的一次只能等待一個事件的到來。
3>信號驅動I/O
在TCPsocket中發(fā)生以下事件均會產生SIGIO信號,因為在同一個時候產生這種信號的原因太多我們不能區(qū)分到底是哪一種情況產生的SIGIO信號,所以在TCP中信號驅動是不太適合使用的,相反在UDP中卻比較適合使用。
信號驅動的工作方式如下圖所示
4>I/O多路復用。
這種方式下的工作方式就比較特別了,按TCPsocket來舉例,他會當listen到一個新的鏈接的時候將它放到一個集合中,當這個集合中的套接字有讀的情況,我們便讀取,有寫的情況,我們便寫,它是非阻塞I/O和信號驅動I/O再加上可以等待多個,這三個的合體,常見的函數(shù)有select,poll,epoll等,這些函數(shù)會在后面的博客中細細講述。
它的缺點就是,無論是上面所述的哪種函數(shù),每次發(fā)送或者接受一個數(shù)據(jù)都會進入兩次內核與用戶的轉換。
I/O多路復用的模型如下圖
5>異步I/O
當一個異步過程調用發(fā)出后,調用者不能立刻得到結果。實際處理這個調用的部件在完成后,通過狀態(tài)、通知和回調來通知調用者的輸入輸出操作
5種I/O模型的對比如下圖
可以看出最好的方式是異步I/O了當然它實現(xiàn)起來比較負責,阻塞I/O的可靠性最好。