舉個讀socket
的例子,假定經過長時間的沉默後,現在來了100個位元組,這時無論邊緣觸發和條件觸發都會產生乙個read ready notification
通知應用程式可讀。應用程式讀了50個位元組,然後重新呼叫api
等待io
事件。
這時條件觸發的api
會因為還有50個位元組可讀從而立即返回使用者乙個read ready notification
。而邊緣觸發的api
會因為可讀這個狀態沒有發生變化而陷入長期等待。
因此在使用邊緣觸發的api
時,要注意每次都要讀到socket
返回ewouldblock
為止,否則這個socket
就算廢了。而使用條件觸發的api
時,如果應用程式不需要寫就不要關注socket
可寫的事件,否則就會無限次的立即返回乙個write ready notification
。大家常用的select
就是屬於條件觸發這一類,長期關注socket
寫事件會出現cpu
100%的毛病。
支援乙個程序開啟大數目的socket
描述符(fd
)
select
最不能忍受的是乙個程序所開啟的fd
是有一定限制的,由fd_setsize
設定,預設值是2048
。對於那些需要支援的上萬連線數目的im伺服器來說顯然太少了。這時候你一是可以選擇修改這個巨集然後重新編譯核心,不過資料也同時指出這樣會帶來網路效率的下降,二是可以選擇多程序的解決方案(傳統的apache
方案),不過雖然linux
上面建立程序的代價比較小,但仍舊是不可忽視的,加上程序間資料同步遠比不上執行緒間同步的高效,所以也不是一種完美的方案。不過epoll
則沒有這個限制,它所支援的fd
上限是最大可以開啟檔案的數目,這個數字一般遠大於2048
,舉個例子,在1gb
記憶體的機器上大約是10
萬左右,具體數目可以cat /proc/sys/fs/file-max
察看,一般來說這個數目和系統記憶體關係很大。
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
之上了。
使用mmap
加速核心與使用者空間的訊息傳遞。
這點實際上涉及到epoll
的具體實現了。無論是select
,poll
還是epoll
都需要核心把fd
訊息通知給使用者空間,如何避免不必要的記憶體拷貝就 很重要,在這點上,epoll
是通過核心於使用者空間mmap
同一塊記憶體實現的。而如果你想我一樣從2.5核心就關注epoll
的話,一定不會忘記手工mmap
這一步的。
核心微調
這一點其實不算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
網絡卡驅動架構。
epoll的 LT 條件觸發和 ET 邊緣觸發
下面是二者的定義 條件觸發 lt 只要輸入緩衝有資料就會一直通知該事件 邊緣觸發 et 輸入緩衝收到資料時僅註冊1次該事件,即使輸入緩衝中還留有資料,也不會再進行註冊 從而我要說明的是,為什麼要強調邊緣觸發要使用非阻塞io 因為在伺服器端當epoll wait監聽到有客戶端fd可讀寫時,那麼就只會返...
epoll 水平觸發 邊緣觸發
水平觸發 只要緩衝區還有資料,核心就還會通知使用者。使用者如果第一次讀取資料沒讀完,即使沒有任何新的操作觸發,還是可以繼續通過epoll wait來獲取事件 邊緣觸發 只有當新事件觸發的時候,才能通過epoll wait來獲取資料,如果第一次讀取資料沒讀完,就只能等待下一次事件觸發來獲取餘下的資料。...
epoll 水平觸發 邊緣觸發
先簡單比較一下level trigger 和 edge trigger 模式的不同。讓我們換乙個角度來理解et模式,事實上,epoll的et模式其實就是socket io完全狀態機。當socket由不可讀變成可讀時,epoll的et模式返回read 事件。對於read 事件,開發者需要保證把讀取緩衝...