在深入理解select、poll和epoll之間的區別之前,首先要了解什么是IO多路復用模型,
IO多路復用
簡單來說,IO多路復用是指內核一旦發現行程指定的一個或者多個IO條件準備就緒,它就通知該行程去進行IO操作,
詳細的描述可以參考IO模型,select、poll和epoll都是提供I/O多路復用的解決方案,
select
- 函式
int select(int maxfdp, fd_set *readset, fd_set *writeset,
fd_set *exceptset, struct timeval *timeout);
- 基本原理:select 函式監視的檔案描述符分3類,分別是
writefds、readfds、和exceptfds,呼叫select時會被阻塞,直到有fd就緒(讀、寫、或者例外),或者超時(timeout指定等待時間,如果立即回傳設為null即可)函式回傳一個大于0的值,然后通過遍歷檔案描述符集合fd_set,來找到就緒的描述符 - 說明:
maxfdp是一個整數值,是指集合中所有檔案描述符的范圍,即所有檔案描述符的最大值加1,fd_set是以位圖的形式來存盤這些檔案描述符,maxfdp也就是定義了位圖中有效地位的個數 - 時間復雜度:
O(n),n為檔案描述符集合fd_set的大小 - 檔案描述符最大限制:
1024
poll
- 函式
int poll ( struct pollfd * fds, unsigned int nfds, int timeout);
- 基本原理:和select 函式很相似,定義了一個
struct pollfd結構型別的陣列,用于存放需要檢測其狀態的所有檔案描述符,呼叫poll函式之后,系統不會清空這個陣列,特別是對于檔案描述符比較多的情況下,在一定程度上可以提高處理的效率,這一點與select()函式不同,呼叫select()函式之后,select()函式會清空它所檢測的檔案描述符集合,導致每次呼叫select()之前都必須把檔案描述符重新加入到待檢測的集合中,因此,select()函式適合于只檢測一個檔案描述符的情況,而poll()函式適合于大量檔案描述符的情況 - 時間復雜度:
O(n),n為檔案描述符集合的大小 - 檔案描述符最大限制:無限制,
fds是一個鏈表
epoll
- 函式
// 建立一個epoll物件,引數size是內核保證能夠正確處理的最大句柄數
int epoll_create(int size);
// 操作上面建立的epoll
// 例如,將剛建立的socket加入到epoll中讓其監控,或者
// 把 epoll正在監控的某個socket句并移出epoll
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
// 在指定的timeout時間內,當所有句柄中有事件發生時,就回傳給用戶態的行程
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
- 基本原理:將所有的檔案描述符
fd_set存盤在共享記憶體(用戶空間和內核空間都可以直接訪問),呼叫epoll_create函式創建epoll物件,并以紅黑樹的結構存盤在內核空間,epoll_ctl函式用來在紅黑樹中添加或者注銷待監視檔案描述符,最后呼叫epoll_wait函式直到有就緒的檔案描述符立即回傳給用戶態行程

- 時間復雜度:
O(1) - 檔案描述符最大限制:能打開的fd的上限遠大于
1024(1G的記憶體上能監聽約10w+)
epoll的兩種作業方式
- 水平觸發(LT):若就緒的事件一次沒有處理完所有要做的事件,就會一直去處理,即就會將沒有處理完的事件繼續放回到就緒佇列之中(即那個內核中的鏈表),一直進行處理
- 邊緣觸發(ET) :就緒的事件只能處理一次,若沒有處理完會在下次的其它事件就緒時再進行處理,而若以后再也沒有就緒的事件,那么剩余的那部分資料也會隨之而丟失,
ET模式的效率比LT模式的效率要高很多,只是如果使用ET模式,就要保證每次進行資料處理時,要將其處理完,不能造成資料丟失,這樣對撰寫代碼的人要求就比較高, 為了保證資料的完整性,ET模式只支持非阻塞的讀寫,
select、poll和epoll對比
| 實作機制 | 時間復雜度 | 連接數 | 傳遞方式 |
|---|---|---|---|
| select | O(n) |
1024 |
內核-->用戶 |
| poll | O(n) |
無限制 | 內核-->用戶 |
| epoll | O(1) |
很大 | 共享記憶體 |
在select和poll中,行程只有在呼叫方法后,內核才對所有監視的檔案描述符進行掃描,發現有任何一個檔案描述符就緒或者超時就立刻回傳,epoll采用基于事件的就緒通知方式,事先通過epoll_ctl()來注冊一個檔案描述符,一旦基于某個檔案描述符就緒時,內核會采用類似callback的回呼機制,迅速激活這個檔案描述符,當行程呼叫epoll_wait()時便得到通知,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/145075.html
標籤:Java
上一篇:IO模型
