select、poll和epoll的區別


操作系統在處理io的時候,主要有兩個階段:

  • 等待數據傳到io設備
  • io設備將數據復制到user space

我們一般將上述過程簡化理解為:

  • 等到數據傳到kernel內核space
  • kernel內核區域將數據復制到user space(理解為進程或者線程的緩沖區)

  select,poll,epoll都是IO多路復用的機制。I/O多路復用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進行相應的讀寫操作。但select,poll,epoll本質上都是同步I/O,因為他們都需要在讀寫事件就緒后自己負責進行讀寫,也就是說這個讀寫過程是阻塞的,而異步I/O則無需自己負責進行讀寫,異步I/O的實現會負責把數據從內核拷貝到用戶空間。


 

select

  單個進程就可以同時處理多個網絡連接的io請求(同時阻塞多個io操作)。基本原理就是程序呼叫select,然后整個程序就阻塞狀態,這時候,kernel內核就會輪詢檢查所有select負責的文件描述符fd,當找到其中那個的數據准備好了文件描述符,會返回給select,select通知系統調用,將數據從kernel內核復制到進程緩沖區(用戶空間)。

下圖為select同時從多個客戶端接受數據的過程

雖然服務器進程會被select阻塞,但是select會利用內核不斷輪詢監聽其他客戶端的io操作是否完成


Poll介紹

poll的原理與select非常相似,差別如下:

  • 描述fd集合的方式不同,poll使用 pollfd 結構而不是select結構fd_set結構,所以poll是鏈式的,沒有最大連接數的限制
  • poll有一個特點是水平觸發,也就是通知程序fd就緒后,這次沒有被處理,那么下次poll的時候會再次通知同個fd已經就緒。

select的幾大缺點:

(1)每次調用select,都需要把fd集合從用戶態拷貝到內核態,這個開銷在fd很多時會很大

(2)同時每次調用select都需要在內核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大

(3)select支持的文件描述符數量太小了,默認是1024


細談事件驅動-->epoll

epoll 提供了三個函數:

  • int epoll_create(int size);
    建立一個 epoll 對象,並傳回它的id

  • int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    事件注冊函數,將需要監聽的事件和需要監聽的fd交給epoll對象

  • int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
    等待注冊的事件被觸發或者timeout發生

epoll解決的問題:

  • epoll沒有fd數量限制
    epoll沒有這個限制,我們知道每個epoll監聽一個fd,所以最大數量與能打開的fd數量有關,一個g的內存的機器上,能打開10萬個左右

  • epoll不需要每次都從用戶空間將fd_set復制到內核kernel
    epoll在用epoll_ctl函數進行事件注冊的時候,已經將fd復制到內核中,所以不需要每次都重新復制一次

  • select 和 poll 都是主動輪詢機制,需要遍歷每一個人fd;
    epoll是被動觸發方式,給fd注冊了相應事件的時候,我們為每一個fd指定了一個回調函數,當數據准備好之后,就會把就緒的fd加入一個就緒的隊列中,epoll_wait的工作方式實際上就是在這個就緒隊列中查看有沒有就緒的fd,如果有,就喚醒就緒隊列上的等待者,然后調用回調函數。

  • 雖然epoll。poll。epoll都需要查看是否有fd就緒,但是epoll之所以是被動觸發,就在於它只要去查找就緒隊列中有沒有fd,就緒的fd是主動加到隊列中,epoll不需要一個個輪詢確認。
    換一句話講,就是select和poll只能通知有fd已經就緒了,但不能知道究竟是哪個fd就緒,所以select和poll就要去主動輪詢一遍找到就緒的fd。而epoll則是不但可以知道有fd可以就緒,而且還具體可以知道就緒fd的編號,所以直接找到就可以,不用輪詢。

總結

  • select, poll是為了解決同時大量IO的情況(尤其網絡服務器),但是隨着連接數越多,性能越差
  • epoll是select和poll的改進方案,在 linux 上可以取代 select 和 poll,可以處理大量連接的性能問題


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM