多路複用IO模型中的select和epoll
多路複用IO模型中的select和epoll
一,前提知識——檔案描述符fd
1、檔案描述符簡介
首先從檔案描述符開始講起。因為,對於核心而言,所有開啟的檔案都是通過檔案描述符引用的。那麼檔案描述符到底是什麼?
檔案描述符(file descriptor)通常是一個小的非負整數,核心用以標識一個特定程序正在訪問的檔案。當開啟一個現有檔案或建立一個新檔案時,核心向程序返回一個檔案描述符。當讀、寫一個檔案時,使用 open 或 create 返回的檔案描述符標識該檔案,將其作為引數傳送給 read 或 write。
我的理解,檔案描述符就是核心用來標識某程序正在訪問檔案的一個標誌。
二,概念介紹
select,poll,epoll都是IO多路複用的機制。I/O多路複用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程式進行相應的讀寫操作。但select,poll,epoll本質上都是同步I/O,因為他們都需要在讀寫事件就緒後自己負責進行讀寫,也就是說這個讀寫過程是阻塞的,而非同步I/O則無需自己負責進行讀寫,非同步I/O的實現會負責把資料從核心拷貝到使用者空間。
三,select流程
1, 拿到所有需要輪詢的檔案描述符fd,從使用者空間拷貝到核心空間。
2, 註冊回撥函式。
3, 遍歷所有的fd。
4, 呼叫poll,返回是否讀寫就緒的mask掩碼。
5,遍歷結束,進入睡眠(超時重新喚起遍歷或者回調epoll喚起)。
6,繼續遍歷,從3開始。
7,結束,將所有fd重新拷貝回用戶空間。
select的幾大缺點:
(1)每次呼叫select,都需要把fd集合從使用者態拷貝到核心態,這個開銷在fd很多時會很大
(2)同時每次呼叫select都需要在核心遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大
(3)select支援的檔案描述符數量太小了,預設是1024
四,epoll的改進
首先在select裡需要在每次呼叫select都會拷貝fd。epoll只拷貝一次。
原因是:
select和poll都只提供了一個函式——select或者poll函式。而epoll提供了三個函式,epoll_create, epoll_ctl 和epoll_wait,epoll_create是建立一個epoll控制代碼;epoll_ctl是註冊要監聽的事件型別;epoll_wait則是等待事件的產生,epoll的解決方案在epoll_ctl函式中。每次註冊新的事件到epoll控制代碼中時(在epoll_ctl中指定EPOLL_CTL_ADD),會把所有的fd拷貝進核心,而不是在epoll_wait的時候重複拷貝。epoll保證了每個fd在整個過程中只會拷貝一次
而且epoll的回撥函式不是返回是否讀寫就緒,而是直接將就緒的fd拷貝加入一個就緒連結串列。所以epoll的遍歷喚醒時不用像select一樣再遍歷一遍fd集合,而只需要看一下就緒連結串列是否為空,如果不為空進行讀寫即可。
還有select有fd的支援數量只有1024,而epoll無限制,只被系統記憶體限制,測試中1G記憶體可以支援10W左右。cat /proc/sys/fs/file-max可以檢視。