epoll高效的原因,從下面幾個方向來說:
文章目錄
select:
select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
根據API,可以看出select需要提供三個文件描述符(內部是位圖,所以只用三個即可),分別監聽讀、寫、異常。
epoll:
epoll_create的時候在內核高速cache中建紅黑樹以及就緒鏈表(存儲已有監聽事件到達的fd)。用戶執行epoll_ctl的時候就會在紅黑樹中增加相應的節點。
select:
採取輪詢的方式,遍歷fd,最後返回一個描述符讀寫操作是否就緒的mask掩碼,根據這個掩碼給fd_set賦值。
epoll:
通過在epoll_ctl的時候想內核註冊回調函數,內核在監測到文件描述符可讀/可寫的時候調用相應的回調,將文件描述符相關的結構體放入就緒鏈表中。
select:
用戶並不知道哪些文件描述符處於就緒狀態,需要遍歷。
epoll:
epoll_wait的時候直接檢查就緒鏈表,返回的fd都是已經就緒的,以此處理即可。
select:
將新的文件描述符重新傳入內核態中,需要重新複製一次。
epoll:
無須重新傳入,直接沿用紅黑樹中節點即可。
在少連接高併發的情況下。
因爲,連接少意味着不會超過select1024的上限,高併發意味着一次wait每一個連接都會來數據。把掃描有事件連接時的O(n)的複雜度降至O(1)。
加上每次只需要複製4次fd_set從內核空間和用戶空間往返,(sizeof(fd_set)=128),總體上比epoll要複製的量要少(sizeof(struct epoll_event)=12)(假設100個連接 12*100=1200)。在這種情況下select是要比epoll高效的。
到這裏延伸一下,如果select支持大量連接,並且每一個連接都是相當活躍的,即還是O(n)->O(1)的情況。那麼select的性能要比epoll高。
也就是說select的差距主要體現在每次內核O(n)的去遍歷fd,用戶也需要去遍歷fd,造成效率低下。