select和epoll區別

socket編程併發處理的問題中,select和epoll函數的區別一直是面試中的重點。關於他倆的區別很多博客中已經說明了,我在這裏總結一下。參考select和epoll 原理概述&優缺點比較以及select、poll、epoll之間的區別總結[整理]

select的過程
調用select函數時到底發生了什麼,即如何實現同時監聽多個socket的。假設我們需要監聽的讀套接字read[],它作爲參數傳遞進了select函數。

select(fd_set read[],fd_set [],fd_set [],timeout)
從用戶空間拷貝fd_set到內核空間,也即從當前程序拷貝fd_set數組進內核,fd_set是什麼可以參考百度百科,簡單的說,是可以對socket進行操作的long型數組。
對所有的fd進行一次poll操作,即把當前進程掛載到fd上。
poll操作過程中select會喚醒所有的隊列中節點,進行遍歷,得到它們的掩碼(不同的掩碼錶示不同的就緒狀態)。
如果所有設備返回的掩碼都沒有顯示任何的事件觸發,就去掉回調函數的函數指針,進入有限時的睡眠狀態,再恢復和不斷做poll,再作有限時的睡眠,直到其中一個設備有事件觸發爲止。
只要有事件觸發,系統調用返回,將fd_set從內核空間拷貝到用戶空間,回到用戶態,用戶就可以對相關的fd作進一步的讀或者寫操作了。
epoll過程
這裏我就直接引用文章[select和epoll 原理概述&優缺點比較]((https://blog.csdn.net/jiange_zh/article/details/50811553)中的話。

調用epoll_create時,做了以下事情:

內核幫我們在epoll文件系統裏建了個file結點;
在內核cache裏建了個紅黑樹用於存儲以後epoll_ctl傳來的socket;
建立一個list鏈表,用於存儲準備就緒的事件。
調用epoll_ctl時,做了以下事情:

把socket放到epoll文件系統裏file對象對應的紅黑樹上;
給內核中斷處理程序註冊一個回調函數,告訴內核,如果這個句柄的中斷到了,就把它放到準備就緒list鏈表裏。
調用epoll_wait時,做了以下事情:
觀察list鏈表裏有沒有數據。有數據就返回,沒有數據就sleep,等到timeout時間到後即使鏈表沒數據也返回。而且,通常情況下即使我們要監控百萬計的句柄,大多一次也只返回很少量的準備就緒句柄而已,所以,epoll_wait僅需要從內核態copy少量的句柄到用戶態而已。

總結一下,就是epoll不需要通過遍歷的方式,而是在內核中建立了file節點,並且通過註冊響應事件的方式,當有響應事件發生時採取相應的措施,並把準備就緒的事件放入鏈表中,從而epoll只關心鏈表中是否有數據即可。

對比
很明顯,select的效率低於epoll,因爲它需要大量拷貝fd_set,並且需要不斷遍歷監聽列表,而epoll這種基於響應事件的方式明顯會更具優勢。

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