論epoll的使用
前幾天回答一個問題,是關于我們項目中使用的epoll模式的,因為記不大清了,感覺應該使用的就是epoll的高速模式,也就是ET(edge-trigger)模式。這兩天閑暇的時候,打開代碼又看了一下,在epoll事件注冊時并未標記ET模式,看來實際使用的是epoll默認的LT(level-trigger )模式,為什么呢?使用LT意味著 只要 fd 處于 readable/writable 狀態,每次 epoll_wait 時都會返回該 fd,系統開銷不說,自己處理時每次都要把這些fd輪詢一遍,如果fd很多的話,不管這些fd有沒有事件發生,epoll_wait 都會觸發這些fd的輪詢判斷。查閱了一些資料,才知道常用的事件處理庫很多都選擇了 LT 模式,包括大家熟知的libevent和boost::asio等,為什么選擇LT呢?那就不得不從ET的弊端的弊端說起。
ET模式下,當有事件發生時,系統只會通知你一次,也就是調用epoll_wait 返回fd后,不管事件你處理與否,或者處理完全與否,再調用epoll_wait 時,都不會再返回該fd,這樣programmer要自己保證在事件發生時及時有效的處理完。比如此時fd發生了EPOLLIN事件,在調用epoll_wait 后發現此事件,programmer要保證在本次輪詢中對此fd進行了讀操作,并且還要循環調用recv操作,一直讀到recv的返回值小于請求值,或者遇到EAGAIN錯誤,不然下次輪詢時,如果此fd沒有再次觸發事件,你就沒有機會知道這個fd需要你的處理。這樣無形中就增加了programmer的負擔和出錯的機會。
ET模式的短處正是LT模式的長處,無論此fd是否有事件發生,或者有事件未處理完,每次epoll_wait 時總會得到此fd供你處理。顯而易見,OS在LT模式下維護的 ready list 的大小肯定比ET模式下長,而且你自己輪詢所有的fd時也要比ET下要多,這種消耗和ET模式下循環調用處理函數(如recv和send等),還要邏輯處理是否處理完畢,理論上應該是LT更大一些,不過個人感覺應該差別不會太大。但是LT模式下帶來的邏輯處理的方便性和不易出錯性,讓我們有理由把它作為首選。我想這可能也是為什么epoll后來在ET的基礎上又增加了LT,并且將其作為默認模式的原因吧。
peakflys 上述觀點,歡迎 志同道合或志同道不合的朋友拍磚。
PS:文中一味寫LT的好處,沒有說LT 極易引起的寫觸發 頻繁通知的問題,具體大家可以參考評論部分,再次感謝大家的指教。
posted on 2012-08-26 18:33 peakflys 閱讀(12743) 評論(18) 編輯 收藏 引用 所屬分類: 服務器