linux epoll總結

什麼是epoll

epoll是什麼?按照man手冊的說法:是爲處理大批量句柄而做了改進的poll。固然,這不是2.6內核纔有的,它是在2.5.44內核中被引進的(epoll(4) is a new API introduced in Linux kernel 2.5.44),它幾乎具有了以前所說的一切優勢,被公認爲Linux2.6下性能最好的多路I/O就緒通知方法。node

epoll的相關係統調用

epoll只有epoll_create,epoll_ctl,epoll_wait 3個系統調用。linux

1. int epoll_create(int size);數組

建立一個epoll的句柄。自從linux2.6.8以後,size參數是被忽略的。須要注意的是,當建立好epoll句柄後,它就是會佔用一個fd值,在linux下若是查看/proc/進程id/fd/,是可以看到這個fd的,因此在使用完epoll後,必須調用close()關閉,不然可能致使fd被耗盡。緩存

2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);服務器

epoll的事件註冊函數,它不一樣於select()是在監聽事件時告訴內核要監聽什麼類型的事件,而是在這裏先註冊要監聽的事件類型。網絡

第一個參數是epoll_create()的返回值。socket

第二個參數表示動做,用三個宏來表示:函數

EPOLL_CTL_ADD:註冊新的fd到epfd中;性能

EPOLL_CTL_MOD:修改已經註冊的fd的監聽事件;ui

EPOLL_CTL_DEL:從epfd中刪除一個fd;

 

第三個參數是須要監聽的fd。

第四個參數是告訴內核須要監聽什麼事,struct epoll_event結構以下:

 

typedef union epoll_data {  
    void *ptr;  
    int fd;  
    __uint32_t u32;  
    __uint64_t u64;  
} epoll_data_t;  
 //感興趣的事件和被觸發的事件  
struct epoll_event {  
    __uint32_t events; /* Epoll events */  
    epoll_data_t data; /* User data variable */  
};

events能夠是如下幾個宏的集合:

EPOLLIN :表示對應的文件描述符能夠讀(包括對端SOCKET正常關閉);

EPOLLOUT:表示對應的文件描述符能夠寫;

EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這裏應該表示有帶外數據到來);

EPOLLERR:表示對應的文件描述符發生錯誤;

EPOLLHUP:表示對應的文件描述符被掛斷;

EPOLLET: 將EPOLL設爲邊緣觸發(Edge Triggered)模式,這是相對於水平觸發(Level Triggered)來講的。

EPOLLONESHOT:只監聽一次事件,當監聽完此次事件以後,若是還須要繼續監聽這個socket的話,須要再次把這個socket加入到EPOLL隊列裏

 

 

3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

收集在epoll監控的事件中已經發送的事件。參數events是分配好的epoll_event結構體數組,epoll將會把發生的事件賦值到events數組中(events不能夠是空指針,內核只負責把數據複製到這個events數組中,不會去幫助咱們在用戶態中分配內存)maxevents告以內核這個events有多大,這個 maxevents的值不能大於建立epoll_create()時的size,參數timeout是超時時間(毫秒,0會當即返回,-1是永久阻塞)。若是函數調用成功,返回對應I/O上已準備好的文件描述符數目,如返回0表示已超時。

 

Epoll的2種工做方式-水平觸發(LT)和邊緣觸發(ET)

 水平觸發(LT):缺省的工做方式,若是一個描述符就緒,內核就會通知處理,若是不進行處理,下一次內核仍是會通知

邊緣觸發(ET):只支持非阻塞描述符。須要程序保證緩存區的數據所有被讀取或者所有寫出(覺得ET模式下,描述符的就緒不會再次通知),所以須要發的非阻塞的描述符。

                              對於讀操做,若是read一次沒有讀盡buffer中的數據,那麼下次將得不到讀就緒的通知,形成buffer中已有的數據無機會讀出,除非有新的數據再次到達。對於寫操做,主要是由於ET模式下fd一般爲非阻塞形成的一個問題——如何保證                              將用戶要求寫的數據寫完。

 

epoll相比於select/poll的優勢:

1.支持一個進程打開大數目的socket描述符(FD)

    select 最不能忍受的是一個進程所打開的FD是有必定限制的,由FD_SETSIZE設置,默認值是2048。對於那些須要支持的上萬鏈接數目的IM服務器來講顯然太少了。這時候你一是能夠選擇修改這個宏而後從新編譯內核,不過資料也同時指出這樣會帶來網絡效率的降低,二是能夠選擇多進程的解決方案(傳統的 Apache方案),不過雖然linux上面建立進程的代價比較小,但仍舊是不可忽視的,加上進程間數據同步遠比不上線程間同步的高效,因此也不是一種完美的方案。不過 epoll則沒有這個限制,它所支持的FD上限是最大能夠打開文件的數目,這個數字通常遠大於2048,舉個例子,在1GB內存的機器上大約是10萬左右,具體數目能夠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加速內核與用戶空間的消息傳遞

    不管是select,poll仍是epoll都須要內核把FD消息通知給用戶空間,如何避免沒必要要的內存拷貝就很重要,在這點上,epoll是經過內核於用戶空間mmap同一塊內存實現的。而若是你想我同樣從2.5內核就關注epoll的話,必定不會忘記手工 mmap這一步的。

 

epoll機理

當某一進程調用epoll_create方法時,Linux內核會建立一個eventpoll結構體,這個結構體中有兩個成員與epoll的使用方式密切相關。eventpoll結構體以下所示:

struct eventpoll{  
    ....  
    /*紅黑樹的根節點,這顆樹中存儲着全部添加到epoll中的須要監控的事件*/  
    struct rb_root  rbr;  
    /*雙鏈表中則存放着將要經過epoll_wait返回給用戶的知足條件的事件*/  
    struct list_head rdlist;  
    ....  
};  

每個epoll對象都有一個獨立的eventpoll結構體,用於存放經過epoll_ctl方法向epoll對象中添加進來的事件。這些事件都會掛載在紅黑樹中,如此,重複添加的事件就能夠經過紅黑樹而高效的識別出來(紅黑樹的插入時間效率是lgn,其中n爲樹的高度)。

而全部添加到epoll中的事件都會與設備(網卡)驅動程序創建回調關係,也就是說,當相應的事件發生時會調用這個回調方法。這個回調方法在內核中叫ep_poll_callback,它會將發生的事件添加到rdlist雙鏈表中。

在epoll中,對於每個事件,都會創建一個epitem結構體,以下所示:

struct epitem{  
    struct rb_node  rbn;//紅黑樹節點  
    struct list_head    rdllink;//雙向鏈表節點  
    struct epoll_filefd  ffd;  //事件句柄信息  
    struct eventpoll *ep;    //指向其所屬的eventpoll對象  
    struct epoll_event event; //期待發生的事件類型  
}

當調用epoll_wait檢查是否有事件發生時,只須要檢查eventpoll對象中的rdlist雙鏈表中是否有epitem元素便可。若是rdlist不爲空,則把發生的事件複製到用戶態,同時將事件數量返回給用戶。

相關文章
相關標籤/搜索