IO模型

io模型:

1.阻塞I/O模型

在linux中,默認情況下所有的socket都是blocking,一個典型的讀操作流程大概是這樣:

 當用戶進程調用了recvfrom這個系統調用,kernel就開始了IO的第一個階段:準備數據。對於network io來說,很多時候數據在一開始還沒有到達(比如,還沒有收到一個完整的UDP包),

這個時候kernel就要等待足夠的數據到來。而在用戶進程這邊,整個進程會被阻塞。當kernel一直等到數據準備好了,它就會將數據從kernel中拷貝到用戶內存,然後kernel返回結果,用戶

進程才解除block的狀態,重新運行起來。所以,blocking IO的特點就是在IO執行的兩個階段(等待數據和拷貝數據兩個階段)都被block了。

eg:老李去火車站買票,排隊三天買到一張退票。
耗費:在車站吃喝拉撒睡 3天,其他事一件沒幹。

 

2.非阻塞I/O模型

 Linux下,可以通過設置socket使其變爲non-blocking。當對一個non-blocking socket執行讀操作時,流程是這個樣子:

從圖中可以看出,當用戶進程發出read操作時,如果kernel中的數據還沒有準備好,那麼它並不會block用戶進程,而是立刻返回一個error。從用戶進程角度講 ,它發起一個read操作後,並不需要等待,

而是馬上就得到了一個結果。用戶進程判斷結果是一個error時,它就知道數據還沒  有準備好,於是它可以再次發送read操作。一旦kernel中的數據準備好了,並且又再次收到了用戶進程的system call,

那麼它馬上就將數據拷貝到了用戶內存,然後返回。所以,在非阻塞式IO中,用戶進程其實是需要不斷的主動詢問kernel數據準備好了沒有。

 

eg:老李去火車站買票,隔12小時去火車站問有沒有退票,三天後買到一張票。耗費:往返車站6次,路上6小時,其他時間做了好多事。

 

3.I/O複用模型   IO multiplexing
    3.1.select/poll

select的優勢在於它可以同時處理多個connection。(多說一句:所以,如果處理的連接數不是很高的話,使用select/epoll的web server不一定比使用multi-threading + blocking IO的web server性能更好,

可能延遲還更大。select/epoll的優勢並不是對於單個連接能處理得更快,而是在於能處理更多的連接。)當用戶進程調用了select,那麼整個進程會被block,而同時,kernel會“監視”所有select負責的socket,

當任何一個socket中的數據準備好了,select就會返回。這個時候用戶進程再調用read操作,將數據從kernel拷貝到用戶進程。


   eg:老李去火車站買票,委託黃牛,然後每隔6小時電話黃牛詢問,黃牛三天內買到票,然後老李去火車站交錢領票。
   耗費:打電話
   3.2.epoll

使用select() 的事件驅動模型只用單線程(進程)執行,佔用資源少,不消耗太多 CPU,同時能夠爲多客戶端提供服務。如果試圖建立一個簡單的事件驅動的服務器程序,這個模型有一定的參考價值。但這

個模型依舊有着很多問題。首先select()接口並不是實現“事件驅動”的最好選擇。因爲當需要探測的句柄值較大時,select()接口本身需要消耗大量時間去輪詢各個句柄。select 最不能忍受的是一個進程所打

開的FD是有一定限制的,由FD_SETSIZE設置,默認值是2048。對於那些需要支持的上萬連接數目的IM服務器來說顯然太少了。 很多操作系統提供了更爲高效的接口,如linux提供了epoll.epoll則沒有這個

限制,它所支持的FD上限是最大可以打開文件的數目,這個數字一般遠大於2048,舉個例子,在1GB內存的機器上大約是10萬左右,具體數目可以cat /proc/sys/fs/file-max查看,一般來說這個數目和系統

內存關係很大。epoll是Linux內核爲處理大批量文件描述符而作了改進的poll,是Linux下多路複用IO接口select/poll的增強版本,它能顯著提高程序在大量併發連接中只有少量活躍的情況下的系統CPU利用

率。在獲取事件的時候,它無須遍歷整個被偵聽的描述符集,只要遍歷那些被內核IO事件異步喚醒而加入Ready隊列的描述符集合就行了。epoll除了提供select/poll那種IO事件的水平觸發(Level Triggered)外,

還提供了邊緣觸發(Edge Triggered),這就使得用戶空間程序有可能緩存IO狀態,減少epoll_wait/epoll_pwait的調用,提高應用程序效率。


   eg:老李去火車站買票,委託黃牛,黃牛買到後即通知老李去領,然後老李去火車站交錢領票。
   耗費:無需打電話

4.信號驅動I/O模型

當一個進程執行IO操作(讀或寫)時,內核馬上返回,進程繼續運行。當剛纔指定的IO操作完成後(或出錯),通過信號通知進程。


eg:老李去火車站買票,給售票員留下電話,有票後,售票員電話通知老李,然後老李去火車站交錢領票。
耗費:無需打電話

5.異步I/O模型

 Linux下的asynchronous IO其實用得不多,從內核2.6版本纔開始引入。先看一下它的流程:

用戶進程發起read操作之後,立刻就可以開始去做其它的事。而另一方面,從kernel的角度,當它受到一個asynchronous read之後,首先它會立刻返回,所以不會對用戶進程產生任何block。然後,

kernel會等待數據準備完成,然後將數據拷貝到用戶內存,當這一切都完成之後,kernel會給用戶進程發送一個signal,告訴它read操作完成了

 

eg:老李去火車站買票,給售票員留下電話,有票後,售票員電話通知老李並快遞送票上門。
耗費:無需打電話

 

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