天天看點

6種epoll的設計,讓你吊打面試官,而且他不能還嘴

select的缺點:

單個程序能夠監視的檔案描述符的數量存在最大限制,通常是1024,當然可以更改數量,但由于select采用輪詢的方式掃描檔案描述符,檔案描述符數量越多,性能越差;(在linux核心頭檔案中,

有這樣的定義:#define __fd_setsize 1024)

核心 / 使用者空間記憶體拷貝問題,select需要複制大量的句柄資料結構,産生巨大的開銷;

select傳回的是含有整個句柄的數組,應用程式需要周遊整個數組才能發現哪些句柄發生了事件;

select的觸發方式是水準觸發,應用程式如果沒有完成對一個已經就緒的檔案描述符進行io操作,那麼之後每次select調用還是會将這些檔案描述符通知程序。

相比select模型,poll使用連結清單儲存檔案描述符,是以沒有了監視檔案數量的限制,但其他三個缺點依然存在。

拿select模型為例,假設我們的伺服器需要支援100萬的并發連接配接,則在__fd_setsize 為1024的情況下,則我們至少需要開辟1k個程序才能實作100萬的并發連接配接。除了程序間上下文切換的時間消耗外,從核心/使用者空間大量的無腦記憶體拷貝、數組輪詢等,是系統難以承受的。是以,基于select模型的伺服器程式,要達到10萬級别的并發通路,是一個很難完成的任務。

是以,該epoll上場了。

epoll io多路複用模型實作機制

==================

由于epoll的實作機制與select/poll機制完全不同,上面所說的 select的缺點在epoll上不複存在。

設想一下如下場景:有100萬個用戶端同時與一個伺服器程序保持着tcp連接配接。而每一時刻,通常隻有幾百上千個tcp連接配接是活躍的(事實上大部分場景都是這種情況)。如何實作這樣的高并發?

在select/poll時代,伺服器程序每次都把這100萬個連接配接告訴作業系統(從使用者态複制句柄資料結構到核心态),讓作業系統核心去查詢這些套接字上是否有事件發生,輪詢完後,再将句柄資料複制到使用者态,讓伺服器應用程式輪詢處理已發生的網絡事件,這一過程資源消耗較大,是以,select/poll一般隻能處理幾千的并發連接配接。

epoll的設計和實作與select完全不同。epoll通過在linux核心中申請一個簡易的檔案系統(檔案系統一般用什麼資料結構實作?b+樹)。把原先的select/poll調用分成了3個部分:

1)調用epoll_create()建立一個epoll對象(在epoll檔案系統中為這個句柄對象配置設定資源)

2)調用epoll_ctl向epoll對象中添加這100萬個連接配接的套接字

3)調用epoll_wait收集發生的事件的連接配接

如此一來,要實作上面說是的場景,隻需要在程序啟動時建立一個epoll對象,然後在需要的時候向這個epoll對象中添加或者删除連接配接。同時,epoll_wait的效率也非常高,因為調用epoll_wait時,并沒有一股腦的向作業系統複制這100萬個連接配接的句柄資料,核心也不需要去周遊全部的連接配接。

epoll 很重要,但是 epoll 與 select 的差別是什麼呢?epoll 高效的原因是什麼?

從網卡接收資料說起

下邊是一個典型的計算機結構圖,計算機由 cpu、存儲器(記憶體)與網絡接口等部件組成,了解 epoll 本質的第一步,要從硬體的角度看計算機怎樣接收網絡資料。

6種epoll的設計,讓你吊打面試官,而且他不能還嘴

計算機結構圖(圖檔來源:linux 核心完全注釋之微型計算機組成結構)

下圖展示了網卡接收資料的過程:

在 1 階段,網卡收到網線傳來的資料。

經過 2 階段的硬體電路的傳輸。

最終 3 階段将資料寫入到記憶體中的某個位址上。

這個過程涉及到 dma 傳輸、io 通路選擇等硬體有關的知識,但我們隻需知道:網卡會把接收到的資料寫入記憶體。

6種epoll的設計,讓你吊打面試官,而且他不能還嘴

網卡接收資料的過程

通過硬體傳輸,網卡接收的資料存放到記憶體中,作業系統就可以去讀取它們。

如何知道接收了資料?

了解 epoll 本質的第二步,要從 cpu 的角度來看資料接收。了解這個問題,要先了解一個概念:中斷。

計算機執行程式時,會有優先級的需求。比如,當計算機收到斷電信号時,它應立即去儲存資料,儲存資料的程式具有較高的優先級(電容可以儲存少許電量,供 cpu 運作很短的一小段時間)。

一般而言,由硬體産生的信号需要 cpu 立馬做出回應,不然資料可能就丢失了,是以它的優先級很高。

cpu 理應中斷掉正在執行的程式,去做出響應;當 cpu 完成對硬體的響應後,再重新執行使用者程式。

中斷的過程如下圖,它和函數調用差不多,隻不過函數調用是事先定好位置,而中斷的位置由“信号”決定。

6種epoll的設計,讓你吊打面試官,而且他不能還嘴