回覆列表
  • 1 # IT達人說

    提到epoll,就不得不提到select,poll了,因為epoll解決的問題,正是select,poll遇到的問題。

    Linux提供了select、poll、epoll介面來實現IO複用,三者的原型如下所示,本文從引數、實現、效能等方面對三者進行對比

    int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); int poll(struct pollfd *fds, nfds_t nfds, int timeout); int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

    select、poll、epoll_wait引數及實現對比

    1. select的第一個引數nfds為fdset集合中最大描述符值加1,fdset是一個位數組,其大小限制為__FD_SETSIZE(1024),位陣列的每一位代表其對應的描述符是否需要被檢查。

    select的第二三四個引數表示需要關注讀、寫、錯誤事件的檔案描述符位陣列,這些引數既是輸入引數也是輸出引數,可能會被核心修改用於標示哪些描述符上發生了關注的事件。所以每次呼叫select前都需要重新初始化fdset。

    timeout引數為超時時間,該結構會被核心修改,其值為超時剩餘的時間。 select對應於核心中的sys_select呼叫,sys_select首先將第二三四個引數指向的fd_set複製到核心,然後對每個被SET的描述符呼叫進行poll,並記錄在臨時結果中(fdset),如果有事件發生,select會將臨時結果寫到使用者空間並返回;當輪詢一遍後沒有任何事件發生時,如果指定了超時時間,則select會睡眠到超時,睡眠結束後再進行一次輪詢,並將臨時結果寫到使用者空間,然後返回。 select返回後,需要逐一檢查關注的描述符是否被SET(事件是否發生)。

    2. poll與select不同,透過一個pollfd陣列向核心傳遞需要關注的事件,故沒有描述符個數的限制,pollfd中的events欄位和revents分別用於標示關注的事件和發生的事件,故pollfd陣列只需要被初始化一次。

    poll的實現機制與select類似,其對應核心中的sys_poll,只不過poll向核心傳遞pollfd陣列,然後對pollfd中的每個描述符進行poll,相比處理fdset來說,poll效率更高。

    poll返回後,需要對pollfd中的每個元素檢查其revents值,來得指事件是否發生。

    epoll與select、poll不同,首先,其不用每次呼叫都向核心複製事件描述資訊,在第一次呼叫後,事件資訊就會與對應的epoll描述符關聯起來。另外epoll不是透過輪詢,而是透過在等待的描述符上註冊回撥函式,當事件發生時,回撥函式負責把發生的事件儲存在就緒事件連結串列中,最後寫到使用者空間。

    epoll返回後,該引數指向的緩衝區中即為發生的事件,對緩衝區中每個元素進行處理即可,而不需要像poll、select那樣進行輪詢檢查。

  • 中秋節和大豐收的關聯?
  • 為什麼中超俱樂部球衣都沒有球員名字別的聯賽有?