I/O模型

本章介紹

I/O介紹

I/O模型

五種I/O模型的對比

I/O模型的具體實現

 

I/O介紹

I/O:

網絡IO:本質是socket讀取

磁盤IO

每次IO,都要經由兩個階段:

第一步:將數據從磁盤文件先加載至內核內存空間(緩衝區),等待數據準備完成,時間較長

第二步:將數據從內核緩衝區複製到用戶空間的進程的內存中,時間較短

 

I/O模型

同步/異步:關注的是消息通信機制

同步:synchronous,調用者等待被調用者返回消息,才能繼續執行

異步:asynchronous,被調用者通過狀態、通知或回調機制主動通知調用者被調用者的運行狀態

阻塞/非阻塞:關注調用者在等待結果返回之前所處的狀態

阻塞:blocking,指IO操作需要徹底完成後才返回到用戶空間,調用結果返回之前,調用者被掛起

非阻塞:nonblocking,指IO操作被調用後立即返回給用戶一個狀態值,無需等到IO操作徹底完成,最終的調用結果返回之前,調用者不會被掛起

I/O模型:

阻塞型、非阻塞型、複用型、信號驅動型、異步

 

同步阻塞IO模型

同步阻塞IO模型.png

同步阻塞IO模型是最簡單的IO模型,用戶線程在內核進行IO操作時被阻塞

用戶線程通過系統調用read發起IO讀操作,由用戶空間轉到內核空間。內核等到數據包到達後,然後將接收的數據拷貝到用戶空間,完成read操作

用戶需要等待read將數據讀取到buffer後,才繼續處理接收的數據。整個IO請求的過程中,用戶線程是被阻塞的,這導致用戶在發起IO請求時,不能做任何事情,對CPU的資源利用率不夠

 

同步非阻塞IO模型

同步非阻塞IO模型.png 

用戶線程發起IO請求時立即返回。但並未讀取到任何數據,用戶線程需要不斷地發起IO請求,直到數據到達後,才真正讀取到數據,繼續執行。即 “輪詢”機制

整個IO請求的過程中,雖然用戶線程每次發起IO請求後可以立即返回,但是爲了等到數據,仍需要不斷地輪詢、重複請求,消耗了大量的CPU的資源

是比較浪費CPU的方式,一般很少直接使用這種模型,而是在其他IO模型中使用非阻塞IO這一特性

 

IO多路複用模型

IO多路複用模型.png 

多個連接共用一個等待機制,本模型會阻塞進程,但是進程是阻塞在select或者poll這兩個系統調用上,而不是阻塞在真正的IO操作上

用戶首先將需要進行IO操作添加到select中,繼續執行做其他的工作(異步),同時等待select系統調用返回。當數據到達時,IO被激活,select函數返回。用戶線程正式發起read請求,讀取數據並繼續執行。

從流程上來看,使用select函數進行IO請求和同步阻塞模型沒有太大的區別,甚至還多了添加監視IO,以及調用select函數的額外操作,效率更差。並且阻塞了兩次,但是第一次阻塞在select上時,select可以監控多個IO上是否已有IO操作準備就緒,即可達到在同一個線程內同時處理多個IO請求的目的。而不像阻塞IO那種,一次只能監控一個IO

雖然上述方式允許單線程內處理多個IO請求,但是每個IO請求的過程還是阻塞的(在select函數上阻塞),平均時間甚至比同步阻塞IO模型還要長。如果用戶線程只是註冊自己需要的IO請求,然後去做自己的事情,等到數據到來時再進行處理,則可以提高CPU的利用率

IO多路複用是最常使用的IO模型,但是其異步程度還不夠“徹底”,因爲它使用了會阻塞線程的select系統調用。因此IO多路複用只能稱爲異步阻塞IO模型,而非真正的異步IO

 

多路I/O複用

IO多路複用是指內核一旦發現進程指定的一個或者多個IO條件準備讀取,就通知該進程

IO多路複用適用如下場合:

當客戶端處理多個描述符時(一般是交互式輸入和網絡套接口),必須使用I/O複用

當一個客戶端同時處理多個套接字時,此情況可能的但很少出現

當一個TCP服務器既要處理監聽套接口,又要處理已連接套接口,一般也要用到I/O複用

當一個服務器即要處理TCP,又要處理UDP,一般要使用I/O複用

當一個服務器要處理多個服務或多個協議,一般要使用I/O複用

 

信號驅動IO模型

信號驅動IO模型.png 

信號驅動IOsignal-driven I/O

用戶進程可以通過sigaction系統調用註冊一個信號處理程序,然後主程序可以繼續向下執行,當有IO操作準備就緒時,由內核通知觸發一個SIGIO信號處理程序執行,然後將用戶進程所需要的數據從內核空間拷貝到用戶空間

此模型的優勢在於等待數據報到達期間進程不被阻塞。用戶主程序可以繼續執行,只要等待來自信號處理函數的通知

該模型並不常用

 

異步IO模型

異步IO模型.png 

異步IO與信號驅動IO最主要的區別是信號驅動IO是由內核通知何時可以進行IO操作,而異步IO則是由內核告訴我們IO操作何時完成了。具體來說就是,信號驅動IO當內核通知觸發信號處理程序時,信號處理程序還需要阻塞在從內核空間緩衝區拷貝數據到用戶空間緩衝區這個階段,而異步IO直接是在第二個階段完成後內核直接通知可以進行後續操作了

相比於IO多路複用模型,異步IO並不十分常用,不少高性能併發服務程序使用IO多路複用模型+多線程任務處理的架構基本可以滿足需求。況且目前操作系統對異步IO的支持並非特別完善,更多的是採用IO多路複用模型模擬異步IO的方式(IO事件觸發時不直接通知用戶線程,而是將數據讀寫完畢後放到用戶指定的緩衝區中)

 

五種I/O模型的對比

 五種IO模型的對比.png

I/O模型的具體實現

主要實現方式有以下幾種:

SelectLinux實現對應,I/O複用模型,BSD4.2最早實現

PollLinux實現,對應I/O複用模型,System V unix最早實現

EpollLinux實現,對應I/O複用模型,具有信號驅動I/O模型的某些特性

KqueueFreeBSD實現,對應I/O複用模型,具有信號驅動I/O模型某些特性

/dev/pollSUNSolaris實現,對應I/O複用模型,具有信號驅動I/O模型的某些特性

Iocp Windows實現,對應第5種(異步I/O)模型

 

select/poll/epoll

select poll epoll 01.png

select poll epoll 02.png

Select:POSIX所規定,目前幾乎在所有的平臺上支持,其良好跨平臺支持也是它的一個優點,本質上是通過設置或者檢查存放fd標誌位的數據結構來進行下一步處理

缺點:

單個進程可監視的fd數量被限制,即能監聽端口的數量有限

cat /proc/sys/fs/file-max

socket是線性掃描,即採用輪詢的方法,效率較低

select 採取了內存拷貝方法來實現內核將 FD 消息通知給用戶空間,這樣一個用來存放大量fd的數據結構,這樣會使得用戶空間和內核空間在傳遞該結構時複製開銷大

 

poll

本質上和select沒有區別,它將用戶傳入的數組拷貝到內核空間,然後查詢每個fd對應的設備狀態

其沒有最大連接數的限制,原因是它是基於鏈表來存儲的

大量的fd的數組被整體複製於用戶態和內核地址空間之間,而不管這樣的複製是不是有意義

poll特點是“水平觸發”,如果報告了fd後,沒有被處理,那麼下次poll時會再次報告該fd

邊緣觸發:只通知一次

 

epoll:在Linux 2.6內核中提出的selectpoll的增強版本

支持水平觸發LT和邊緣觸發ET,最大的特點在於邊緣觸發,它只告訴進程哪些fd剛剛變爲就需態,並且只會通知一次

使用“事件”的就緒通知方式,通過epoll_ctl註冊fd,一旦該fd就緒,內核就會採用類似callback的回調機制來激活該fdepoll_wait便可以收到通知

優點:

沒有最大併發連接的限制:能打開的FD的上限遠大於1024(1G的內存能監聽約10萬個端口)

效率提升:非輪詢的方式,不會隨着FD數目的增加而效率下降;只有活躍可用的FD纔會調用callback函數,即epoll最大的優點就在於它只管理“活躍”的連接,而跟連接總數無關

內存拷貝,利用mmap(Memory Mapping)加速與內核空間的消息傳遞;即epoll使用mmap減少複製開銷

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章