在IO多路複用中select(poll)有諸多限制,不少人會說select的缺點是在Linux內核中,select所用到的FD_SET是有限的,(內核中有個參數__FD_SETSIZE定義了每一個FD_SET的句柄個數)。可是更重要的缺點卻觸及不到:併發
當併發上來後,輪詢的低效率和頻繁的內核態用戶態切換會致使select的性能急劇降低:函數
(0) 紅黑樹是在mmap出的內存上的,減小了用戶空間和內核空間的拷貝
(1) epoll_wait調用ep_poll,當rdlist爲空(無就緒fd)時掛起當前進程,知道rdlist不空時進程才被喚醒。
(2) 文件fd狀態改變(buffer由不可讀變爲可讀或由不可寫變爲可寫),致使相應fd上的回調函數ep_poll_callback()被調用。
(3) ep_poll_callback將相應fd對應epitem加入rdlist,致使rdlist不空,進程被喚醒,epoll_wait得以繼續執行。
(4) ep_events_transfer函數將rdlist中的epitem拷貝到txlist中,並將rdlist清空。
(5) ep_send_events函數,它掃描txlist中的每一個epitem,調用其關聯fd對用的poll方法。以後將取得的events和相應的fd發送到用戶空間(封裝在struct epoll_event,從epoll_wait返回)。
(6) 若是這個epitem對應的fd是LT模式監聽且取得的events是用戶所關心的,則將其從新加入回rdlist。不然(ET模式)不在加入rdlist。性能
ET和LT模式下的epitem均可以經過插入紅黑樹時的回調(ep_poll_callback)方式加入rdlist從而喚醒epoll_wait,但LT模式下的epitem還能夠經過txlist(ep_send_events)從新加入rdlist喚醒epoll_wait。因此ET模式下,fd就緒,只會被通知一次,而LT模式下只要知足相應讀寫條件就返回就緒(經過txlist加入rdlist)。spa
對於讀取操做:blog
(1) 當buffer由不可讀狀態變爲可讀的時候,即由空變爲不空的時候。進程
(2) 當有新數據到達時,即buffer中的待讀內容變多的時候。事件
對於寫操做:ip
(1) 當buffer由不可寫變爲可寫的時候,即由滿狀態變爲不滿狀態的時候。內存
(2) 當有舊數據被髮送走時,即buffer中待寫的內容變少得時候。資源
對於讀操做:
(1) buffer中有數據可讀的時候,即buffer不空的時候fd的events的可讀爲就置1。
對於寫操做:
(1) buffer中有空間可寫的時候,即buffer不滿的時候fd的events的可寫位就置1。
與select相比,epoll的回調機制使得資源可以直接使用在有活動的事件上,而不用線性輪詢全部的事件。同時 epoll經過內核與用戶空間mmap同一塊內存,減小了用戶空間和內核空間的數據交換,解決了select的重要痛點。
另外一方面,LT是epoll的默認操做模式,當epoll_wait函數檢測到有事件發生並將通知應用程序,而應用程序不必定必須當即進行處理,這樣epoll_wait函數再次檢測到此事件的時候還會通知應用程序,直到事件被處理。
而ET模式,只要epoll_wait函數檢測到事件發生,通知應用程序當即進行處理,後續的epoll_wait函數將再也不檢測此事件。所以ET模式在很大程度上下降了同一個事件被epoll觸發的次數,所以效率比LT模式高。