epoll比select和poll高效的原因

我們通過比較select、poll和epoll處理I/O的過程來剖析其中的原因:
1. 用戶態將文件描述符傳入內核的方式:
select:創建3個文件描述符集並拷貝到內核中,分別監聽讀、寫、異常動作。這裏受到單個進程可以打開的fd數量限制,默認是1024。 
poll:將傳入的struct pollfd結構體數組拷貝到內核中進行監聽。 
epoll:執行epoll_create會在內核的高速cache區中建立一顆紅黑樹以及就緒鏈表(該鏈表存儲已經就緒的文件描述符)。接着用戶執行的epoll_ctl函數添加文件描述符會在紅黑樹上增加相應的結點。

2. 內核態檢測文件描述符是否可讀可寫的方式:
select:採用輪詢方式,遍歷所有fd,最後返回一個描述符讀寫操作是否就緒的mask掩碼,根據這個掩碼給fd_set賦值。 
poll:同樣採用輪詢方式,查詢每個fd的狀態,如果就緒則在等待隊列中加入一項並繼續遍歷。 
epoll:採用回調機制。在執行epoll_ctl的add操作時,不僅將文件描述符放到紅黑樹上,而且也註冊了回調函數,內核在檢測到某文件描述符可讀/可寫時會調用回調函數,該回調函數將文件描述符放在就緒鏈表中。

3. 如何找到就緒的文件描述符並傳遞給用戶態:
select:將之前傳入的fd_set拷貝傳出到用戶態並返回就緒的文件描述符總數。用戶態並不知道是哪些文件描述符處於就緒態,需要遍歷來判斷。 
poll:將之前傳入的fd數組拷貝傳出用戶態並返回就緒的文件描述符總數。用戶態並不知道是哪些文件描述符處於就緒態,需要遍歷來判斷。 
epoll:epoll_wait只用觀察就緒鏈表中有無數據即可,最後將鏈表的數據返回給數組並返回就緒的數量。內核將就緒的文件描述符放在傳入的數組中,所以只用遍歷依次處理即可。這裏返回的文件描述符是通過mmap讓內核和用戶空間共享同一塊內存實現傳遞的,減少了不必要的拷貝。

4. 繼續重新監聽時如何重複以上步驟:
select:將新的監聽文件描述符集合拷貝傳入內核中,繼續以上步驟。 
poll:將新的struct pollfd結構體數組拷貝傳入內核中,繼續以上步驟。 
epoll:無需重新構建紅黑樹,直接沿用已存在的即可。

通過以上步驟我們可以發現以下幾點:
select和poll的動作基本一致,只是poll採用鏈表來進行文件描述符的存儲,而select採用fd標註位來存放,所以select會受到最大連接數的限制,而poll不會。
select、poll、epoll雖然都會返回就緒的文件描述符數量。但是select和poll並不會明確指出是哪些文件描述符就緒,而epoll會。造成的區別就是,系統調用返回後,調用select和poll的程序需要遍歷監聽的整個文件描述符找到是誰處於就緒,而epoll則直接處理就行了。
select、poll都需要將有關文件描述符的數據結構拷貝進內核,最後再拷貝出來。而epoll創建的有關文件描述符的數據結構本身就存於內核態中,系統調用返回時也採用mmap共享存儲區,需要拷貝的次數大大減少。
select、poll採用輪詢的方式來檢查文件描述符是否處於就緒態,而epoll採用回調機制。造成的結果就是,隨着fd的增加,select和poll的效率會線性降低,而epoll不會受到太大影響,除非活躍的socket很多。
最後總結一下,epoll比select和poll高效的原因主要有兩點: 
1. 減少了用戶態和內核態之間的文件描述符拷貝 
2. 減少了對就緒文件描述符的遍歷
--------------------- 
作者:Move_now 
來源:CSDN 
原文:https://blog.csdn.net/Move_now/article/details/71773965 
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章