1. 程式人生 > >多路複用IO模型中的select和epoll

多路複用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流程

imagef74c416b09205492.png

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可以檢視。