epoll和select的區別

2020-12-15 電子發燒友

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

  一、問題引出 聯繫區別

  問題的引出,當需要讀兩個以上的I/O的時候,如果使用阻塞式的I/O,那麼可能長時間的阻塞在一個描述符上面,另外的描述符雖然有數據但是不能讀出來,這樣實時性不能滿足要求,大概的解決方案有以下幾種:

  1.使用多進程或者多線程,但是這種方法會造成程序的複雜,而且對與進程與線程的創建維護也需要很多的開銷。(Apache伺服器是用的子進程的方式,優點可以隔離用戶)

  2.用一個進程,但是使用非阻塞的I/O讀取數據,當一個I/O不可讀的時候立刻返回,檢查下一個是否可讀,這種形式的循環為輪詢(polling),這種方法比較浪費CPU時間,因為大多數時間是不可讀,但是仍花費時間不斷反覆執行read系統調用。

  3.異步I/O(asynchronous I/O),當一個描述符準備好的時候用一個信號告訴進程,但是由於信號個數有限,多個描述符時不適用。

  4.一種較好的方式為I/O多路轉接(I/O multiplexing)(貌似也翻譯多路復用),先構造一張有關描述符的列表(epoll中為隊列),然後調用一個函數,直到這些描述符中的一個準備好時才返回,返回時告訴進程哪些I/O就緒。select和epoll這兩個機制都是多路I/O機制的解決方案,select為POSIX標準中的,而epoll為Linux所特有的。

  區別(epoll相對select優點)主要有三

  1.select的句柄數目受限,在linux/posix_types.h頭文件有這樣的聲明:#define __FD_SETSIZE 1024 表示select最多同時監聽1024個fd。而epoll沒有,它的限制是最大的打開文件句柄數目。

  2.epoll的最大好處是不會隨著FD的數目增長而降低效率,在selec中採用輪詢處理,其中的數據結構類似一個數組的數據結構,而epoll是維護一個隊列,直接看隊列是不是空就可以了。epoll只會對「活躍」的socket進行操作---這是因為在內核實現中epoll是根據每個fd上面的callback函數實現的。那麼,只有「活躍」的socket才會主動的去調用 callback函數(把這個句柄加入隊列),其他idle狀態句柄則不會,在這點上,epoll實現了一個「偽」AIO。但是如果絕大部分的I/O都是「活躍的」,每個I/O埠使用率很高的話,epoll效率不一定比select高(可能是要維護隊列複雜)。

  3.使用mmap加速內核與用戶空間的消息傳遞。無論是select,poll還是epoll都需要內核把FD消息通知給用戶空間,如何避免不必要的內存拷貝就很重要,在這點上,epoll是通過內核於用戶空間mmap同一塊內存實現的。

  

  二、接口

  1)select

  1. int select(int maxfdp1, fd_set *restrict readfds, fd_set *restrict writefds, fd_set *restrict exceptfds, struct timeval *restrict tvptr);

  struct timeval{

  long tv_sec;

  long tv_usec;

  }

  有三種情況:tvptr == NULL 永遠等待;tvptr-》tv_sec == 0 && tvptr-》tv_usec == 0 完全不等待;不等於0的時候為等待的時間。select的三個指針都可以為空,這時候select提供了一種比sleep更精確的定時器。注意select的第一個參數maxfdp1並不是描述符的個數,而是最大的描述符加1,一是起限制作用,防止出錯,二來可以給內核輪詢的時候提供一個上屆,提高效率。select返回-1表示出錯,0表示超時,返回正值是所有的已經準備好的描述符個數(同一個描述符如果讀和寫都準備好,對結果影響是+2)。

  2.int FD_ISSET(int fd, fd_set *fdset); fd在描述符集合中非0,否則返回0

  3.int FD_CLR(int fd, fd_set *fd_set); int FD_SET(int fd, fd_set *fdset) ;int FD_ZERO(fd_set *fdset);

  用一段linux 中man裡的話「FD_ZERO() clears a set.FD_SET() and FD_CLR() respectively add and remove a given file descriptor from a set. FD_ISSET() tests to see if a file descriptor is part of the set; this is useful after select() returns.」這幾個函數與描述符的0和1沒關係,只是添加刪除檢測描述符是否在set中。

  2)epoll

  1.int epoll_create(int size);

  創建一個epoll的句柄,size用來告訴內核這個監聽的數目一共有多大。這個參數不同於select()中的第一個參數,給出最大監聽的fd+1的值。需要注意的是,當創建好epoll句柄後,它就是會佔用一個fd值,在linux下如果查看/proc/進程id/fd/,是能夠看到這個fd的,所以在使用完epoll後,必須調用close()關閉,否則可能導致fd被耗盡。

  2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

  epoll的事件註冊函數,它不同與select()是在監聽事件時告訴內核要監聽什麼類型的事件,而是在這裡先註冊要監聽的事件類型。第一個參數是epoll_create()的返回值,第二個參數表示動作,用三個宏來表示:

  EPOLL_CTL_ADD:註冊新的fd到epfd中;

  EPOLL_CTL_MOD:修改已經註冊的fd的監聽事件;

  EPOLL_CTL_DEL:從epfd中刪除一個fd;

  第三個參數是需要監聽的fd,第四個參數是告訴內核需要監聽什麼事,struct epoll_event結構如下:

  struct epoll_event {

  __uint32_t events; /* Epoll events */

  epoll_data_t data; /* User data variable */

  };

  events可以是以下幾個宏的集合:

  EPOLLIN :表示對應的文件描述符可以讀(包括對端SOCKET正常關閉);

  EPOLLOUT:表示對應的文件描述符可以寫;

  EPOLLPRI:表示對應的文件描述符有緊急的數據可讀(這裡應該表示有帶外數據到來);

  EPOLLERR:表示對應的文件描述符發生錯誤;

  EPOLLHUP:表示對應的文件描述符被掛斷;

  EPOLLET: 將EPOLL設為邊緣觸發(Edge Triggered)模式,這是相對於水平觸發(Level Triggered)來說的。

  EPOLLONESHOT:只監聽一次事件,當監聽完這次事件之後,如果還需要繼續監聽這個socket的話,需要再次把這個socket加入到EPOLL隊列裡

  關於epoll工作模式ET,LT

  LT(level triggered)是預設的工作方式,並且同時支持block和no-block socket.在這種做法中,內核告訴你一個文件描述符是否就緒了,然後你可以對這個就緒的fd進行IO操作。如果你不作任何操作,內核還是會繼續通知你的,所以,這種模式編程出錯誤可能性要小一點。傳統的select/poll都是這種模型的代表.

  ET (edge-triggered)是高速工作方式,只支持no-block socket。在這種模式下,當描述符從未就緒變為就緒時,內核通過epoll告訴你。然後它會假設你知道文件描述符已經就緒,並且不會再為那個文件描述符發送更多的就緒通知,直到你做了某些操作導致那個文件描述符不再為就緒狀態了,但是請注意,如果一直不對這個fd作IO操作(從而導致它再次變成未就緒),內核不會發送更多的通知(only once)

  3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)

  等待事件的產生,類似於select()調用。參數events用來從內核得到事件的集合,maxevents告之內核這個events有多大,這個maxevents的值不能大於創建epoll_create()時的size,參數timeout是超時時間(毫秒,0會立即返回,-1永久阻塞)。該函數返回需要處理的事件數目,如返回0表示已超時。

  

打開APP閱讀更多精彩內容

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容圖片侵權或者其他問題,請聯繫本站作侵刪。 侵權投訴

相關焦點

  • (二十五)深入淺出TCPIP之 epoll和select,poll的區別
    在現在的Linux內核裡有都能夠支持,其中epoll是Linux所特有,而select則應該是POSIX所規定,一般作業系統均有實現。        那麼這篇文章,我就來介紹下他們之間的區別。(2)poll==>時間複雜度O(n)poll本質上和select沒有區別,它將用戶傳入的數組拷貝到內核空間,然後查詢每個fd對應的設備狀態, 但是它沒有最大連接數的限制,原因是它是基於鍊表來存儲的.
  • 吊打面試官 | BAT都在問-從底層理解select和epoll的區別
    視頻後還附有文字版本哦▼《BAT都在問-如何從底層角度理解select和epoll的區別》▼ps:請在WiFi環境下打開,如果有錢任性請隨意
  • linux開發各種I/O操作簡析,以及select、poll、epoll機制的對比
    同步IO和異步IO的區別就在於:數據拷貝的時候進程是否阻塞阻塞IO和非阻塞IO的區別就在於:應用程式的調用是否立即返回因為異步IO把IO的操作給了內核,讓內核去操作,同步IO的話,需要等待IO操作從內核態的數據緩衝區拷貝到用戶態的數據緩衝區
  • epoll原理簡介
    epoll是Linux引以為榮的技術,因為相對於select和poll有很大的性能改進。
  • 介紹一下 Android Handler 中的 epoll 機制?
    與多進程和多線程技術相比,IO 多路復用技術的最大優勢是系統開銷小,系統不必為每個 IO 操作都創建進程或線程,也不必維護這些進程或線程,從而大大減小了系統的開銷。select、poll、epoll 就是 IO 多路復用三種實現方式。
  • Golang是怎麼利用epoll的
    系統內核會為每個socket句柄分配一個讀(接收)緩衝區和一個寫(發送)緩衝區,發送數據就是在這個fd對應的寫緩衝區上寫數據,而接收數據就是在讀緩衝區上讀數據,當程序調用write或者send時,並不代表數據發送出去,僅僅是把數據拷貝到了寫緩衝區,在時機恰當時候(積累到一定數量),會將數據發送到目的端。
  • 從linux源碼看epoll
    和select、poll等系統調用相比,epoll在需要監視大量文件描述符並且其中只有少數活躍的時候,表現出無可比擬的優勢。epoll能讓內核記住所關注的描述符,並在對應的描述符事件就緒的時候,在epoll的就緒鍊表中添加這些就緒元素,並喚醒對應的epoll等待進程。
  • 追加查詢 select into from和insert into select的區別
  • Linux系統編程 / triggerhappy 源碼分析(3.select 的應用)
    ()、poll() 和 epoll()。本文先將學習重點放在 select() 上,同時也稍微了解一下 poll() 和 epoll(),明確三者的優缺點。poll() 系統調用會把輸入 (events 成員) 和輸出 (revents 成員) 分離開,無需重新初始化數組就可以重新使用。5.2 對比 epollepoll 是 Linux 特有的 I/O 多路復用解決方案。
  • I/O多路復用之select
    select函數作用  select,poll,epoll都是IO多路復用的機制。
  • 35-python高級篇-C10K問題和io多路復用
    不過此處的select仍是阻塞方式,但區別於while循環獲取一個請求的可用狀態,select可以監聽多個文件句柄和socket狀態[即可傳入list形式的socket數據,select對該list中的所有socket進行監聽,有一個可用時即做返回],期間不存在輪詢過程。    存在問題:在判斷某個socket準備好後,調用recvfrom時仍存在一段時間做內存數據拷貝的操作。
  • 【23期】請你談談關於IO同步、異步、阻塞、非阻塞的區別
    IO multiplexingIO multiplexing這個詞可能有點陌生,但是如果我說select,epoll,大概就都能明白了。有些地方也稱這種IO方式為event driven IO。我們都知道,select/epoll的好處就在於單個process就可以同時處理多個網絡連接的IO。
  • select、pselect和poll函數的區別及用法
    下面我們說一下select、pselect和poll函數的具體用法及區別• select
  • select函數
    一個socket對應著一個ip+埠號,而網絡數據包中包含了ip和埠的信息,所以內核可以找到對應的socket。 假定,用戶當前有三個線程A,B和C被調度器調度執行。線程A已經創建好了sockets,且與多個客戶端成功連接,現在要做的是檢測多個客戶端是否有數據到達。
  • Linux使用epoll異步發送http請求
    它與上一行的\r\n正好構成連續的2個回車換行,這可以用來判斷http頭的結束和正文的開始。把這行字符串發送到伺服器,然後讀取返回結果,就是伺服器的應答。應答可能是個html文件,也可以是其他文件,或者一個flv的動態視頻流(直播一般使用http-flv)。
  • 【英語詞彙】choose, pick, select的用法區別
    區別一choose 的名詞形式為 choice(可數),pick 的名詞形式仍為 pick(不可數),select 的名詞形式為