【轉】IO模型及select、poll、epoll和kqueue的區別

(一)首先,介紹幾種常見的I/O模型及其區別,以下:

  • blocking I/Ohtml

  • nonblocking I/Ojava

  • I/O multiplexing (select and poll)react

  • signal driven I/O (SIGIO)linux

  • asynchronous I/O (the POSIX aio_functions)—————異步IO模型最大的特色是 完成後發回通知。編程

    阻塞與否,取決於實現IO交換的方式。windows

         異步阻塞是基於select,select函數自己的實現方式是阻塞的,而採用select函數有個好處就是它能夠同時監聽多個文件句柄.設計模式

         異步非阻塞直接在完成後通知,用戶進程只須要發起一個IO操做而後當即返回,等IO操做真正的完成之後,應用程序會獲得IO操做完成的通知,此時用戶進程只須要對數據進行處理就行了,不須要進行實際的IO讀寫操做,由於真正的IO讀取或者寫入操做已經由內核完成了。數組

 

 

1 blocking I/O 

這個不用多解釋吧,阻塞套接字。下圖是它調用過程的圖示:服務器

 

重點解釋下上圖,下面例子都會講到。首先application調用 recvfrom()轉入kernel,注意kernel有2個過程,wait for data和copy data from kernel to user。直到最後copy complete後,recvfrom()才返回。此過程一直是阻塞的。網絡

 

2 nonblocking I/O: 

與blocking I/O對立的,非阻塞套接字,調用過程圖以下:

 

能夠看見,若是直接操做它,那就是個輪詢。。直到內核緩衝區有數據。

 

3 I/O multiplexing (select and poll) 

最多見的I/O複用模型,select。

 

select先阻塞,有活動套接字才返回。與blocking I/O相比,select會有兩次系統調用,可是select能處理多個套接字。

 

4 signal driven I/O (SIGIO) 

只有UNIX系統支持,感興趣的課查閱相關資料

 

I/O multiplexing (select and poll)相比,它的優點是,免去了select的阻塞與輪詢,當有活躍套接字時,由註冊的handler處理。

 

5 asynchronous I/O (the POSIX aio_functions) 

不多有*nix系統支持,windows的IOCP則是此模型

 

徹底異步的I/O複用機制,由於縱觀上面其它四種模型,至少都會在由kernel copy data to appliction時阻塞。而該模型是當copy完成後才通知application,可見是純異步的。好像只有windows的完成端口是這個模型,效率也很出色。

6 下面是以上五種模型的比較

能夠看出,越日後,阻塞越少,理論上效率也是最優。

=====================分割線==================================

5種模型的比較比較清晰了,剩下的就是把select,epoll,iocp,kqueue按號入座那就OK了。

select和iocp分別對應第3種與第5種模型,那麼epoll與kqueue呢?其實也於select屬於同一種模型,只是更高級一些,能夠看做有了第4種模型的某些特性,如callback機制。

爲何epoll,kqueue比select高級? 

答案是,他們無輪詢。由於他們用callback取代了。想一想看,當套接字比較多的時候,每次select()都要經過遍歷FD_SETSIZE個Socket來完成調度,無論哪一個Socket是活躍的,都遍歷一遍。這會浪費不少CPU時間。若是能給套接字註冊某個回調函數,當他們活躍時,自動完成相關操做,那就避免了輪詢,這正是epoll與kqueue作的。

windows or *nix (IOCP or kqueue/epoll)?

 

誠然,Windows的IOCP很是出色,目前不多有支持asynchronous I/O的系統,可是因爲其系統自己的侷限性,大型服務器仍是在UNIX下。並且正如上面所述,kqueue/epoll 與 IOCP相比,就是多了一層從內核copy數據到應用層的阻塞,從而不能算做asynchronous I/O類。可是,這層小小的阻塞無足輕重,kqueue與epoll已經作得很優秀了。

提供一致的接口,IO Design Patterns

實際上,無論是哪一種模型,均可以抽象一層出來,提供一致的接口,廣爲人知的有ACE,Libevent(基於reactor模式)這些,他們都是跨平臺的,並且他們自動選擇最優的I/O複用機制,用戶只需調用接口便可。說到這裏又得說說2個設計模式,Reactor and Proactor。見:Reactor模式--VS--Proactor模式Libevent是Reactor模型,ACE提供Proactor模型。實際都是對各類I/O複用機制的封裝。

Java nio包是什麼I/O機制?

 如今能夠肯定,目前的java本質是select()模型,能夠檢查/jre/bin/nio.dll得知。至於java服務器爲何效率還不錯。。我也不得而知,多是設計得比較好吧。。-_-。

=====================分割線==================================

總結一些重點:

  1. 只有IOCP是asynchronous I/O,其餘機制或多或少都會有一點阻塞。
  2. select低效是由於每次它都須要輪詢。但低效也是相對的,視狀況而定,也可經過良好的設計改善
  3. epoll, kqueue、select是Reacor模式,IOCP是Proactor模式。
  4. java nio包是select模型。。

(二)epoll 與select的區別

 

1. 使用多進程或者多線程,可是這種方法會形成程序的複雜,並且對與進程與線程的建立維護也須要不少的開銷。(Apache服務器是用的子進程的方式,優勢能夠隔離用戶)  (同步阻塞IO)

 

2.一種較好的方式爲I/O多路轉接(I/O multiplexing)(貌似也翻譯多路複用),先構造一張有關描述符的列表(epoll中爲隊列),而後調用一個函數,直到這些描述符中的一個準備好時才返回,返回時告訴進程哪些I/O就緒。select和epoll這兩個機制都是多路I/O機制的解決方案,select爲POSIX標準中的,而epoll爲Linux所特有的。

 

區別(epoll相對select優勢)主要有三:

1.select的句柄數目受限,在linux/posix_types.h頭文件有這樣的聲明:#define __FD_SETSIZE    1024  表示select最多同時監聽1024個fd。而epoll沒有,它的限制是最大的打開文件句柄數目。

 

2.epoll的最大好處是不會隨着FD的數目增加而下降效率,在selec中採用輪詢處理,其中的數據結構相似一個數組的數據結構,而epoll是維護一個隊列,直接看隊列是否是空就能夠了。epoll只會對"活躍"的socket進行操做---這是由於在內核實現中epoll是根據每一個fd上面的callback函數實現的。那麼,只有"活躍"的socket纔會主動的去調用 callback函數(把這個句柄加入隊列),其餘idle狀態句柄則不會,在這點上,epoll實現了一個"僞"AIO。可是若是絕大部分的I/O都是「活躍的」,每一個I/O端口使用率很高的話,epoll效率不必定比select高(多是要維護隊列複雜)。

 

3.使用mmap加速內核與用戶空間的消息傳遞。不管是select,poll仍是epoll都須要內核把FD消息通知給用戶空間,如何避免沒必要要的內存拷貝就很重要,在這點上,epoll是經過內核於用戶空間mmap同一塊內存實現的。

 

關於epoll工做模式ET,LT    

 

epoll有兩種工做方式

ET:Edge Triggered,邊緣觸發。僅當狀態發生變化時纔會通知,epoll_wait返回。換句話,就是對於一個事件,只通知一次。且只支持非阻塞的socket。

LT:Level Triggered,電平觸發(默認工做方式)。相似select/poll,只要還有沒有處理的事件就會一直通知,以LT方式調用epoll接口的時候,它就至關於一個速度比較快的poll.支持阻塞和不阻塞的socket。

 

三 Linux併發網絡編程模型

 

    1  Apache 模型,簡稱 PPC ( Process Per Connection ,):爲每一個鏈接分配一個進程。主機分配給每一個鏈接的時間和空間上代價較大,而且隨着鏈接的增多,大量進程間切換開銷也增加了。很難應對大量的客戶併發鏈接。

    2  TPC 模型( Thread Per Connection ):每一個鏈接一個線程。和PCC相似。

    3  select 模型:I/O多路複用技術。

       .1 每一個鏈接對應一個描述。select模型受限於 FD_SETSIZE即進程最大打開的描述符數linux2.6.35爲1024,實際上linux每一個進程所能打開描數字的個數僅受限於內存大小,然而在設計select的系統調用時,倒是參考FD_SETSIZE的值。可經過從新編譯內核更改此值,但不能根治此問題,對於百萬級的用戶鏈接請求  即使增長相應 進程數, 仍顯得杯水車薪呀。

      .2select每次都會掃描一個文件描述符的集合,這個集合的大小是做爲select第一個參數傳入的值。可是每一個進程所能打開文件描述符如果增長了 ,掃描的效率也將減少。

      .3內核到用戶空間,採用內存複製傳遞文件描述上發生的信息。 

  4 poll 模型:I/O多路複用技術。poll模型將不會受限於FD_SETSIZE,由於內核所掃描的文件 描述符集合的大小是由用戶指定的,即poll的第二個參數。但仍有掃描效率和內存拷貝問題。

 5 pselect模型:I/O多路複用技術。同select。

 6 epoll模型:

    .1)無文件描述字大小限制僅與內存大小相關

   .2)epoll返回時已經明確的知道哪一個socket fd發生了什麼事件,不用像select那樣再一個個比對。

  .3)內核到用戶空間採用共享內存方式,傳遞消息。

四 :FAQ  

一、單個epoll並不能解決全部問題,特別是你的每一個操做都比較費時的時候,由於epoll是串行處理的。 因此你有仍是必要創建線程池來發揮更大的效能。 

二、若是fd被註冊到兩個epoll中時,若是有時間發生則兩個epoll都會觸發事件。

三、若是註冊到epoll中的fd被關閉,則其會自動被清除出epoll監聽列表。
四、若是多個事件同時觸發epoll,則多個事件會被聯合在一塊兒返回。
五、epoll_wait會一直監聽epollhup事件發生,因此其不須要添加到events中。
六、爲了不大數據量io時,et模式下只處理一個fd,其餘fd被餓死的狀況發生。linux建議能夠在fd聯繫到的結構中增長ready位,而後epoll_wait觸發事件以後僅將其置位爲ready模式,而後在下邊輪詢ready fd列表。

 

 

參考:

http://blog.csdn.net/ysu108/article/details/7570571

http://techbbs.zol.com.cn/1/8_2245.html

 

 

轉自:http://blog.csdn.net/wenbingoon/article/details/9004512

相關文章
相關標籤/搜索