當乙個節點和多個節點建立連線時,如何高效的處理多個連線的資料,下面具體分析兩者的區別。
1. select函式
函式原型:int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
引數介紹:(1)nfds -- fdset集合中最大描述符值加1
(2)fdset -- 乙個位陣列,其大小限制為_fd_setsize(1024)
位陣列的每一位代表的是其對應的描述符是否需要被檢查。
(3)readfds -- 讀事件檔案描述符陣列
(4 )writefds -- 寫事件檔案描述符陣列
(5)exceptfds -- 錯誤事件檔案描述符陣列
(6)timeout -- 超時事件,該結構被核心修改,其值為超時剩餘時間。
對應核心:select
對應於核心中的
sys_select
呼叫,sys_select
首先將第二三四個引數指向的
fd_set
拷貝到核心,然後對每個被
set的描 述符呼叫進行
poll
,並記錄在臨時結果中(
fdset
),如果有事件發生,
select
會將臨時結果寫到使用者空間並返回;當輪詢一遍後沒有任何事件發生時,如果指定了超時時間,則
select
會睡眠到超時,睡眠結束後再進行一次輪詢,並將臨時結果寫到使用者空間,然後返
2. select/poll特點
傳統的select/poll每次呼叫都會線性掃瞄全部的集合,導致效率呈現線性下降。
poll的執行分三部分:
(1).將使用者傳入的pollfd陣列拷貝到核心空間,因為拷貝操作和陣列長度相關,時間上這是乙個o(n)操作
(2).查詢每個檔案描述符對應裝置的狀態,如果該裝置尚未就緒,則在該裝置的等待佇列中加入一項並繼續查詢下一裝置的狀態。 查詢完所有裝置後如果沒有乙個裝置就緒,這時則需要掛起當前程序等待,直到裝置就緒或者超時。裝置就緒後程序被通知繼續執行,這時再次遍歷所有裝置,以查詢就緒裝置。這一步因為兩次遍歷所有裝置,時間複雜度也是o(n),這裡面不包括等待時間......
(3). 將獲得的資料傳送到使用者空間並執行釋放記憶體和剝離等待佇列等善後工作,向使用者空間拷貝資料與剝離等待佇列等操作的的時間複雜度同樣是o(n)。
3. epoll機制
linux 2.6核心完全支援epoll。epoll的io效率不隨fd數目增加而線性下降。
要使用epoll只需要這三個系統呼叫:epoll_create(2), epoll_ctl(2), epoll_wait(2)
epoll用到的所有函式都是在標頭檔案sys/epoll.h中宣告的,核心實現中epoll是根據每個fd上面的callback函式實現的。只有"活躍"的socket才會主動的去呼叫 callback函式,其他idle狀態socket則不會。
如果所有的socket基本上都是活躍的---比如乙個高速lan環境,過多使用epoll,效率相比還有稍微的下降。但是一旦使用idle connections模擬wan環境,epoll的效率就遠在select/poll之上了。
3.1 所用到的函式:
(1)、int epoll_create(intsize)
該函式生成乙個epoll專用的檔案描述符,其中的引數是指定生成描述符的最大範圍
(2)、int epoll_ctl(intepfd, intop, intfd, struct epoll_event *event)
用於控制某個檔案描述符上的事件,可以註冊事件,修改事件,刪除事件。
如果呼叫成功返回0,不成功返回-1
int epoll_ctl
(3)、int epoll_wait(intepfd
, struct epoll_event * events
,int maxevents,inttimeout
)用於輪詢i/o事件的發生,返回發生事件數
int epoll_wait
epoll是為處理大批量控制代碼而作了改進的poll。
4. epoll的優點:
<1>支援乙個程序開啟大數目的socket描述符(fd)
select 最不能忍受的是乙個程序所開啟的fd是有一定限制的,由fd_setsize設定,預設值是2048。對於那些需要支援的上萬連線數目的im伺服器來說顯然太少了。這時候可以:
(1) 可以修改這個巨集然後重新編譯核心,不過資料也同時指出,這樣也會帶來網路效率的下降
(2) 可以選擇多程序的解決方案,不過雖然linux上建立程序的代價比較下,但是仍舊是不可忽視的,所以也不是很完美的方案
epoll沒有這樣的限制,它所支援的fd上限是最大可以開啟檔案的數目,這個數字一般遠大於2048,具體陣列可以檢視cat /proc/sys/fs/file-max檢視,這個數目和系統記憶體關係很大。
<2>io效率不隨fd數目增加而線性下降
傳統的select/poll另乙個致命弱點就是當你擁有乙個很大的socket集合,不過由於網路延時,任一時間只有部分的socket是"活躍"的,但是select/poll每次呼叫都會線性掃瞄全部的集合,導致效率呈現線性下降。
epoll不存在這個問題,它只會對「活躍」的socket進行操作。
這是因為在核心實現中epoll是根據每個fd上面的callback函式實現的。那麼,只有"活躍"的socket才會主動的去呼叫 callback函式,其他idle狀態socket則不會,在這點上,epoll實現了乙個"偽"aio,因為這時候推動力在os核心。在一些 benchmark中,如果所有的socket基本上都是活躍的---比如乙個高速lan環境,epoll並不比select/poll有什麼效率,相 反,如果過多使用epoll_ctl,效率相比還有稍微的下降。但是一旦使用idle connections模擬wan環境,epoll的效率就遠在select/poll之上了。
<3>使用mmap加速核心與使用者空間的訊息傳遞這點實際上涉及到epoll的具體實現了。無論是select,poll還是epoll都需要核心把fd訊息通知給使用者空間,如何避免不必要的記憶體拷貝就 很重要,在這點上,epoll是通過核心於使用者空間mmap同一塊記憶體實現的。而如果你想我一樣從2.5核心就關注epoll的話,一定不會忘記手工 mmap這一步的。
<4>核心微調
這一點其實不算epoll的優點了,而是整個linux平台的優點。也許你可以懷 疑linux平台,但是你無法迴避linux平台賦予你微調核心的能力。比如,核心tcp/ip協議棧使用記憶體池管理sk_buff結構,那麼可以在執行 時期動態調整這個記憶體pool(skb_head_pool)的大小--- 通過echo ***x>/proc/sys/net/core/hot_list_length完成。再比如listen函式的第2個引數(tcp完成3次握手 的資料報佇列長度),也可以根據你平台記憶體大小動態調整。更甚至在乙個資料報面數目巨大但同時每個資料報本身大小卻很小的特殊系統上嘗試最新的napi網 卡驅動架構。
Select和epoll的區別
當乙個節點和多個節點建立連線時,如何高效的處理多個連線的資料,下面具體分析兩者的區別。1.select函式 函式原型 int select int nfds,fd set readfds,fd set writefds,fd set exceptfds,struct timeval timeout ...
Select和epoll的區別
當乙個節點和多個節點建立連線時,如何高效的處理多個連線的資料,下面具體分析兩者的區別。1.select函式 函式原型 int select int nfds,fd set readfds,fd set writefds,fd set exceptfds,struct timeval timeout ...
epoll和select的區別
做以簡單區分為面試作答提供一些幫助 select 和 epoll都為一種網路i o模型,都是採用了檢測了控制代碼集合中的資料,來實現多路復用。select檔案控制代碼檢測數有限,核心中 fd setsize定義為2048超出範圍將無法檢測,在掃瞄上select 採用的是輪詢的方式當檢測的量太大時會造...