select和epoll模型的區別

1.select epoll模型

1.1.IO模型概述

     通常來,網IO可以抽象成用戶態和內核態之間的數據交換。一次網絡數據讀取操作(read),可以拆分成兩個步驟:1)網卡驅動等待數據準備好(內核態)2)將數據從內核空間拷貝到進程空間(用戶態)。根據這兩個步驟處理方式不一樣,我們通常把網絡IO劃分成阻塞IO和非阻塞IO。

      ·阻塞IO。用戶調用網IO相關的系統調(例如read),如果此內核網卡沒有取到網數據,那麼本次系統調用將會一直阻塞,直到對端系統發送的數據到達爲止。如果對端一直沒有發送數據,則本次調用將永遠不會返回。

      · 非阻塞IO。當用戶調用網IO相關的系統調(例如read),如果此內核網絡還沒有收到網數據,那麼本次系統調用將會立即返回,並返回一個EAGAIN錯誤碼

在沒有IO多路複用技之前,由於沒有一種好的方式來探IO是否可可寫。因此,了增加系的並發連接量,一般是藉助多程或多程的方式來增加系的並發連接數。但是種方式有個問題就是系的並發連接數受限於操作系的最大程或程數,並且隨着操作系程或程數增加,將會引大量的上下文切致系的性能急下降。瞭解決問題,操作系引入了IO多路接技IO multiplexing)。

1.2.  IO多路技術

    IO多路轉接技術其實就是使用select、epoll等操作系統提供的系統調用來檢測IO事件的各種機制。通過select、epoll等機制,我們可以很輕鬆的同時管理大量的網絡IO連接,並且獲取到處於活躍狀態的連接。當其中一個或多個發生網絡IO事件時,select、epoll等系統調用就會返回相應的連接,我們就可以對這些連接進行讀取或寫入操作,從而完成網絡數據交互。

1.3.select 工作原理

       select函數原型:

        int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);

          select各個參數明:

               ·  nfds

這個參數的值一般設置爲讀集合(readfds)、寫集合(writefds)以及exceptfds(異常集合)中最大的描述符(fd)+1,當然也可以設置爲FD_SETSIZE。FD_SETSIZE是操作系統定義的一個宏,一般是1024。也就是說讀寫以及異常集合大小的最大值是1024,所以使用select最多隻能管理1024個連接。如果大於1024個連接,select將會產生不確定行爲。

· readfds

指向可讀描述符集的指針,如果我們關心連接的可讀事件,需要把連接的描述符設置到讀集合中。

·writefds

指向可寫描述符集的指,如果我關心接的可寫事件,需要把接的描述符置到可寫集合中。

· exceptfds

指向異常描述符集的指,如果我關心接的是否生異常,需要把接的描述符置到異常描述符集合中。

·timeout

select願意等待的時間

                      struct timeval {

                                           longtv_sec;      //秒數

                                           longtv_usec;    //微秒數

                                   }

                一般來,分三種情況:

·timeout空,select將會永等待。直到有接可讀、可寫或者被信號中斷時返回。

·timeout->tv_sec = 0 且 timeout->tv_usec = 0,完全不等待。檢測所有指定的描述符後立即返回。這是得到多個描述符的狀態而不阻塞select函數的輪詢方法。

·timeout->tv_sec != 且 timeout->tv_usec != 0,等待指定的秒數和微秒數。當指定的描述符之一已經準備好,或者超過了指定的時間值,則立即返回。如果超時了,還沒有一個描述符準備好,則返回0。

     select的工作原理,select過輪詢來檢測各個集合中的描述符fd)的狀,如果描述符的狀態發生改變,則會在該集合中設置相應的標記位;如果指定描述符的狀態沒有發生改變,則將該描述符從對應集合中移除。因此,select的調用複雜度是線性的,即O(n)。舉個例子,一個保姆照看一羣孩子,如果把孩子是否需要尿尿比作網絡IO事件,select的作用就好比這個保姆挨個詢問每個孩子:你要尿尿嗎?如果孩子回答是,保姆則把孩子拎出來放到另外一個地方。當所有孩子詢問完之後,保姆領着這些要尿尿的孩子去上廁所(處理網絡IO事件)。

    select的限制,前面提到FD_SETSIZE宏,這個宏是操作系統定義的。在linux下面通常是1024,也就是說select最多隻能管理1024個描述符。如果大於1024的個描述,select將會產生不可預知的行爲。那在沒有poll或epoll的情況下,怎樣使用select來處理連接數大於1024的情況呢?答案是使用多線程技術,每個線程單獨使用一個select進行檢測。這樣的話,你的系統能夠處理的併發連接數等於線程數*1024。早期的apache就是這種技術來支撐海量連接的。

1.4.epoll工作原理

  epoll函數原型:

        int epoll_create(int size);

        intepoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

 

                int epoll_wait(intepfd,  struct epoll_event *events, intmaxevents,  int timeout);

         epoll上述三個函數,既可以完成成千上萬的並發連接管理。epoll使用方式,1)通epoll_create建立epoll句柄。2)將描述符所感趣的事件通epoll_ctl添加到epoll句柄中。3調epoll_wait返回所有可寫的描述符。

  epollLinux內核爲處理大批量文件描述符而作了改epoll,是Linux下多路複用IO接口select/poll的增版本,它能著提高程序在大量發連中只有少量活的情況下的系CPU利用率。另一點原因就是取事件的候,它無整個被聽的描述符集,只要遍那些被內核IO事件異步醒而加入Ready列的描述符集合就行了。epoll除了提供select/poll那種IO事件的水平觸Level Triggered)外,提供了邊緣Edge Triggered),就使得用程序有可能IO,減少epoll_wait/epoll_pwait調用,提高用程序效率。

      還是以保姆照看一羣孩子爲例,在epoll機制下,保姆不再需要挨個的詢問每個孩子是否需要尿尿。取而代之的是,每個孩子如果自己需要尿尿的時候,自己主動的站到事先約定好的地方,而保姆的職責就是查看事先約定好的地方是否有孩子。如果有小孩,則領着孩子去上廁所(網絡事件處理)。因此,epoll的這種機制,能夠高效的處理成千上萬的併發連接,而且性能不會隨着連接數增加而下降。

1.5.selectepoll

上所述,selectepoll比如下表所示


select

epoll

性能

隨着接數增加,急下降。理成千上萬並發連接數,性能很差。

隨着接數增加,性能基本上沒有下降。理成千上萬並發連,性能很好。

接數

連接數有限制,處理的最大連接數不超過1024。如果要處理超過1024個連接數,則需要修改FD_SETSIZE宏,並重新編譯 。

接數無限制。

內在處理機制

線性輪詢

回調callback

開發複雜性

 

老男孩教育最新課程selectepoll簡單區別比喻

select的調用複雜度是線性的,即O(n)。舉個例子,一個保姆照看一羣孩子,如果把孩子是否需要尿尿比作網絡IO事件,select的作用就好比這個保姆挨個詢問每個孩子:你要尿尿嗎?如果孩子回答是,保姆則把孩子拎出來放到另外一個地方。當所有孩子詢問完之後,保姆領着這些要尿尿的孩子去上廁所(處理網絡IO事件)。

還是以保姆照看一羣孩子爲例,在epoll機制下,保姆不再需要挨個的詢問每個孩子是否需要尿尿。取而代之的是,每個孩子如果自己需要尿尿的時候,自己主動的站到事先約定好的地方,而保姆的職責就是查看事先約定好的地方是否有孩子。如果有小孩,則領着孩子去上廁所(網絡事件處理)。因此,epoll的這種機制,能夠高效的處理成千上萬的併發連接,而且性能不會隨着連接數增加而下降。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章