導航:首頁 > 廢水知識 > 伺服器多線程epoll效率提升

伺服器多線程epoll效率提升

發布時間:2022-09-20 00:49:22

① select、pool、epoll重點總結

select,poll,epoll都是IO多路復用的機制。I/O多路復用就是通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進行相應的讀寫操作。
但select,poll,epoll本質上都是同步I/O ,因為他們都需要在讀寫事件就緒後自己負責進行讀寫,也就是說這個讀寫過程是阻塞的,而非同步I/O則無需自己負責進行讀寫,非同步I/O的實現會負責把數據從內核拷貝到用戶空間。
I/O復用模型會用到select、poll、epoll函數:對一個IO埠,兩次調用,兩次返回,比阻塞IO並沒有什麼優越性。但關鍵是 能實現同時對多個IO埠進行監聽。
這幾個函數也會使進程阻塞,但是和阻塞I/O所不同的是,這幾個函數 可以同時阻塞多個I/O操作。而且可以同時對多個讀操作,多個寫操作的I/O函數進行檢測,直到有數據可讀或可寫時,才真正調用I/O操作函數。

當一個客戶端連接上伺服器時,伺服器就將其連接的fd加入fd_set集合,等到這個連接准備好讀或寫的時候,就通知程序進行IO操作,與客戶端進行數據通信。大部分Unix/Linux 都支持 select 函數,該函數用於探測多個文件描述符的狀態變化。

(1) 創建所關注的事件的描述符集合(fd_set),對於一個描述符,可以關注其上面的讀(read)、寫(write)、異常(exception)事件,所以通常,要創建三個fd_set,一個用來收集關注讀事件的描述符,一個用來收集關注寫事件的描述符,另外一個用來收集關注異常事件的描述符集合。
(2)調用select()等待事件發生。這里需要注意的一點是,select的阻塞與是否設置非阻塞I/O是沒有關系的。
(3) 輪詢所有fd_set中的每一個fd,檢查是否有相應的事件發生,如果有,就進行處理。

優點:
相比其他模型,使用 select() 的事件驅動模型只用單線程(進程)執行,佔用資源少,不消耗太多 CPU,同時能夠為多客戶端提供服務。如果試圖建立一個簡單的事件驅動的伺服器程序,這個模型有一定的參考價值。
缺點:
(1)每次調用select,都需要把fd集合從用戶態拷貝到內核態,這個開銷在fd很多時會很大!!!(復制大量句柄數據結構,產生巨大的開銷 )。
(2)同時每次調用select都需要在內核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大!!!(消耗大量時間去輪詢各個句柄,才能發現哪些句柄發生了事件)。
(3)單個進程能夠監視的文件描述符的數量存在最大限制,32位機默認是1024。
(4)select的觸發方式是水平觸發,應用程序如果沒有完成對一個已經就緒的文件描述符進行IO操作,那麼之後每次select調用還是會將這些文件描述符通知進程。
(5)該模型將事件探測和事件響應夾雜在一起,一旦事件響應的執行體龐大,則對整個模型是災難性的。

poll庫是在linux2.1.23中引入的,windows平台不支持poll。poll本質上和select沒有太大區別,都是先創建一個關注事件的描述符的集合,然後再去等待這些事件發生,然後再輪詢描述符集合,檢查有沒有事件發生,如果有,就進行處理。因此,poll有著與select相似的處理流程:

(1)select需要為讀、寫、異常事件分別創建一個描述符集合,最後輪詢的時候,需要分別輪詢這三個集合。而poll只需要一個集合,在每個描述符對應的結構上分別設置讀、寫、異常事件,最後輪詢的時候,可以同時檢查三種事件。
(2)它沒有最大連接數的限制,原因是它是基於鏈表來存儲的。

(1)大量的fd的數組被整體復制於用戶態和內核地址空間之間,而不管這樣的復制是不是有意義。
(2)poll還有一個特點是「水平觸發」,如果報告了fd後,沒有被處理,那麼下次poll時會再次報告該fd。

poll和select,它們的最大的問題就在於效率。它們的處理方式都是創建一個事件列表,然後把這個列表發給內核,返回的時候,再去輪詢檢查這個列表,這樣在描述符比較多的應用中,效率就顯得比較低下了。
epoll是一種比較好的做法,它把描述符列表交給內核,一旦有事件發生,內核把發生事件的描述符列表通知給進程,這樣就避免了輪詢整個描述符列表。
epoll支持水平觸發和邊緣觸發,最大的特點在於邊緣觸發,它只告訴進程哪些fd剛剛變為就緒態,並且只會通知一次。還有一個特點是,epoll使用「事件」的就緒通知方式,通過epoll_ctl注冊fd,一旦該fd就緒,內核就會採用類似callback的回調機制來激活該fd,epoll_wait便可以收到通知。
epoll與select和poll的調用介面上的不同:select和poll都只提供了一個函數——select或者poll函數。而epoll提供了三個函數,epoll_create,epoll_ctl和epoll_wait,epoll_create是創建一個epoll句柄;epoll_ctl是注冊要監聽的事件類型;epoll_wait則是等待事件的產生。

(1)創建一個epoll描述符,調用epoll_create()來完成。epoll_create()有一個整型的參數size,用來告訴內核,要創建一個有size個描述符的事件列表(集合)。

(2)給描述符設置所關注的事件,並把它添加到內核的事件列表中。這里需要調用epoll_ctl()來完成。

(3)等待內核通知事件發生,得到發生事件的描述符的結構列表。該過程由epoll_wait()完成。得到事件列表後,就可以進行事件處理了。

(1)沒有最大並發連接的限制,能打開FD的上限遠大於1024(1G的內存上能監聽約10萬個埠);

(2)效率提升。不是輪詢的方式,不會隨著FD數目的增加效率下降。只有活躍可用的FD才會調用callback函數;
即epoll最大的優點就在於它只管你「活躍」的連接,而跟連接總數無關,因此在實際的網路環境中,epoll的效率就會遠遠高於select和poll。
(3)內存拷貝。epoll通過內核和用戶空間共享一塊內存來實現消息傳遞的。利用mmap()文件映射內存加速與內核空間的消息傳遞;即epoll使用mmap 減少復制開銷。epoll保證了每個fd在整個過程中只會拷貝一次(select,poll每次調用都要把fd集合從用戶態往內核態拷貝一次)。

參考鏈接:
select、poll、epoll總結及ET、LT區別

② 為什麼epoll會那麼高效

你好,希望我的回答對你有幫助 1. Epoll是何方神聖? Epoll可是當前在Linux下開發大規模並發網路程序的熱門人選,Epoll 在Linux2.6內核中正式引入,和select相似,其實都I/O多路復用技術而已,並沒有什麼神秘的。 其實在Linux下設計並發網路程序,向來不缺少方法,比如典型的Apache模型(Process Per Connection,簡稱PPC),TPC(Thread PerConnection)模型,以及select模型和poll模型,那為何還要再引入Epoll這個東東呢?那還是有得說說的… 2. 常用模型的缺點 如果不擺出來其他模型的缺點,怎麼能對比出Epoll的優點呢。 2.1 PPC/TPC模型 這兩種模型思想類似,就是讓每一個到來的連接一邊自己做事去,別再來煩我。只是PPC是為它開了一個進程,而TPC開了一個線程。可是別煩我是有代價的,它要時間和空間啊,連接多了之後,那麼多的進程/線程切換,這開銷就上來了;因此這類模型能接受的最大連接數都不會高,一般在幾百個左右。 2.2 select模型 1. 最大並發數限制,因為一個進程所打開的FD(文件描述符)是有限制的,由FD_SETSIZE設置,默認值是1024/2048,因此Select模型的最大並發數就被相應限制了。自己改改這個FD_SETSIZE?想法雖好,可是先看看下面吧… 2. 效率問題,select每次調用都會線性掃描全部的FD集合,這樣效率就會呈現線性下降,把FD_SETSIZE改大的後果就是,大家都慢慢來,什麼?都超時了??!! 3. 內核/用戶空間內存拷貝問題,如何讓內核把FD消息通知給用戶空間呢?在這個問題上select採取了內存拷貝方法。 2.3 poll模型 基本上效率和select是相同的,select缺點的2和3它都沒有改掉。 3. Epoll的提升 把其他模型逐個批判了一下,再來看看Epoll的改進之處吧,其實把select的缺點反過來那就是Epoll的優點了。 3.1. Epoll沒有最大並發連接的限制,上限是最大可以打開文件的數目,這個數字一般遠大於2048, 一般來說這個數目和系統內存關系很大,具體數目可以cat /proc/sys/fs/file-max察看。 3.2. 效率提升,Epoll最大的優點就在於它只管你「活躍」的連接,而跟連接總數無關,因此在實際的網路環境中,Epoll的效率就會遠遠高於select和poll。 3.3. 內存拷貝,Epoll在這點上使用了「共享內存」,這個內存拷貝也省略了。 4. Epoll為什麼高效 Epoll的高效和其數據結構的設計是密不可分的,這個下面就會提到。 首先回憶一下select模型,當有I/O事件到來時,select通知應用程序有事件到了快去處理,而應用程序必須輪詢所有的FD集合,測試每個FD是否有事件發生,並處理事件;代碼像下面這樣: int res = select(maxfd+1, &readfds, NULL, NULL, 120); if(res > 0) { for (int i = 0; i < MAX_CONNECTION; i++) { if (FD_ISSET(allConnection[i], &readfds)) { handleEvent(allConnection[i]); } } } // if(res == 0) handle timeout, res < 0 handle error Epoll不僅會告訴應用程序有I/0 事件到來,還會告訴應用程序相關的信息,這些信息是應用程序填充的,因此根據這些信息應用程序就能直接定位到事件,而不必遍歷整個FD 集合。 intres = epoll_wait(epfd, events, 20, 120); for(int i = 0; i < res;i++) { handleEvent(events[n]); } 5. Epoll關鍵數據結構 前面提到Epoll速度快和其數據結構密不可分,其關鍵數據結構就是: structepoll_event { __uint32_t events; // Epoll events epoll_data_t data; // User data variable }; typedefunion epoll_data { void *ptr; int fd; __uint32_t u32; __uint64_t u64; } epoll_data_t; 可見epoll_data是一個union結構體,藉助於它應用程序可以保存很多類型的信息:fd、指針等等。有了它,應用程序就可以直接定位目標了。 6. 使用Epoll 既然Epoll相比select這么好,那麼用起來如何呢?會不會很繁瑣啊…先看看下面的三個函數吧,就知道Epoll的易用了。 int epoll_create(int size); 生成一個Epoll專用的文件描述符,其實是申請一個內核空間,用來存放你想關注的socket fd上是否發生以及發生了什麼事件。size就是你在這個Epoll fd上能關注的最大socket fd數,大小自定,只要內存足夠。 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event ); 控制某個Epoll文件描述符上的事件:注冊、修改、刪除。其中參數epfd是epoll_create()創建Epoll專用的文件描述符。相對於select模型中的FD_SET和FD_CLR宏。 int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout); 等待I/O事件的發生;參數說明: epfd:由epoll_create() 生成的Epoll專用的文件描述符; epoll_event:用於回傳代處理事件的數組; maxevents:每次能處理的事件數; timeout:等待I/O事件發生的超時值; 返回發生事件數。 相對於select模型中的select函數。 7. 例子程序 下面是一個簡單Echo Server的例子程序,麻雀雖小,五臟俱全,還包含了一個簡單的超時檢查機制,簡潔起見沒有做錯誤處理。

③ select和epoll的區別 知乎

先說下本文框架,先是問題引出,然後概括兩個機制的區別和聯系,最後介紹每個介面的用法
一、問題引出 聯系區別
問題的引出,當需要讀兩個以上的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表示已超時。

④ epoll為什麼這么快epoll的實現原理是什麼

以一個生活中的例子來解釋.假設你在大學中讀書,要等待一個朋友來訪,而這個朋友只知道你在A號樓,但是不知道你具體住在哪裡,於是你們約好了在A號樓門口見面.如果你使用的阻塞IO模型來處理這個問題,那麼你就只能一直守候在A號樓門口等待朋友的到來,...

⑤ 高性能網路伺服器編程:為什麼linux下epoll

基本的IO編程過程(包括網路IO和文件IO)是,打開文件描述符(windows是handler,Java是stream或channel),多路捕獲(Multiplexe,即select和poll和epoll)IO可讀寫的狀態,而後可以讀寫的文件描述符進行IO讀寫,由於IO設備速度和CPU內存比速度會慢,為了更好的利用CPU和內存,會開多線程,每個線程讀寫一個文件描述符。
但C10K問題,讓我們意識到在超大數量的網路連接下,機器設備和網路速度不再是瓶頸,瓶頸在於操作系統和IO應用程序的溝通協作的方式。
舉個例子,一萬個socket連接過來,傳統的IO編程模型要開萬個線程來應對,還要注意,socket會關閉打開,一萬個線程要不斷的關閉線程重建線程,資源都浪費在這上面了,我們算建立一個線程耗1M內存,1萬個線程機器至少要10G內存,這在IA-32的機器架構下基本是不可能的(要開PAE),現在x64架構才有可能舒服點,要知道,這僅僅是粗略算的內存消耗。別的資源呢?
所以,高性能的網路編程(即IO編程),第一,需要松綁IO連接和應用程序線程的對應關系,這就是非阻塞(nonblocking)、非同步(asynchronous)的要求的由來(構造一個線程池,epoll監控到有數的fd,把fd傳入線程池,由這些worker thread來讀寫io)。第二,需要高性能的OS對IO設備可讀寫(數據來了)的通知方式:從level-triggered notification到edge-triggered notification,關於這個通知方式,我們稍後談。
需要注意非同步,不等於AIO(asynchronous IO),Linux的AIO和java的AIO都是實現非同步的一種方式,都是渣,這個我們也接下來會談到。
針對前面說的這兩點,我們看看select和poll的問題
這兩個函數都在每次調用的時候要求我們把需要監控(看看有沒有數據)的文件描述符,通過數組傳遞進入內核,內核每次都要掃描這些文件描述符,去理解它們,建立一個文件描述符和IO對應的數組(實際內核工作會有好點的實現方式,但可以這么理解先),以便IO來的時候,通知這些文件描述符,進而通知到進程里等待的這些select、poll。當有一萬個文件描述符要監控的時候呢(一萬個網路連接)?這個工作效率是很低的,資源要求卻很高。
我們看epoll
epoll很巧妙,分為三個函數,第一個函數創建一個session類似的東西,第二函數告訴內核維持這個session,並把屬於session內的fd傳給內核,第三個函數epoll_wait是真正的監控多個文件描述符函數,只需要告訴內核,我在等待哪個session,而session內的fd,內核早就分析過了,不再在每次epoll調用的時候分析,這就節省了內核大部分工作。這樣每次調用epoll,內核不再重新掃描fd數組,因為我們維持了session。
說道這里,只有一個字,開源,贊,眾人拾柴火焰高,贊。
epoll的效率還不僅僅體現在這里,在內核通知方式上,也改進了,我們先看select和poll的通知方式,也就是level-triggered notification,內核在被DMA中斷,捕獲到IO設備來數據後,本來只需要查找這個數據屬於哪個文件描述符,進而通知線程里等待的函數即可,但是,select和poll要求內核在通知階段還要繼續再掃描一次剛才所建立的內核fd和io對應的那個數組,因為應用程序可能沒有真正去讀上次通知有數據後的那些fd,應用程序上次沒讀,內核在這次select和poll調用的時候就得繼續通知,這個os和應用程序的溝通方式效率是低下的。只是方便編程而已(可以不去讀那個網路io,方正下次會繼續通知)。
於是epoll設計了另外一種通知方式:edge-triggered notification,在這個模式下,io設備來了數據,就只通知這些io設備對應的fd,上次通知過的fd不再通知,內核不再掃描一大堆fd了。
基於以上分析,我們可以看到epoll是專門針對大網路並發連接下的os和應用溝通協作上的一個設計,在linux下編網路伺服器,必然要採用這個,nginx、PHP的國產非同步框架swool、varnish,都是採用這個。
注意還要打開epoll的edge-triggered notification。而java的NIO和NIO.2都只是用了epoll,沒有打開edge-triggered notification,所以不如JBoss的Netty。
接下來我們談談AIO的問題,AIO希望的是,你select,poll,epoll都需要用一個函數去監控一大堆fd,那麼我AIO不需要了,你把fd告訴內核,你應用程序無需等待,內核會通過信號等軟中斷告訴應用程序,數據來了,你直接讀了,所以,用了AIO可以廢棄select,poll,epoll。
但linux的AIO的實現方式是內核和應用共享一片內存區域,應用通過檢測這個內存區域(避免調用nonblocking的read、write函數來測試是否來數據,因為即便調用nonblocking的read和write由於進程要切換用戶態和內核態,仍舊效率不高)來得知fd是否有數據,可是檢測內存區域畢竟不是實時的,你需要在線程里構造一個監控內存的循環,設置sleep,總的效率不如epoll這樣的實時通知。所以,AIO是渣,適合低並發的IO操作。所以java7引入的NIO.2引入的AIO對高並發的網路IO設計程序來說,也是渣,只有Netty的epoll+edge-triggered notification最牛,能在linux讓應用和OS取得最高效率的溝通。

⑥ 單線程epoll的瓶頸在哪裡,如何進一步提升

就是雙核CPU,每個核心2線程(HT)2個就4線程,比如INTEL I3就是這樣線程技術HT作用 盡管提高CPU的時鍾頻率和增加緩存容量後的確可以改善性能,但這樣的CPU性能提高在技術上存在較大的難度。實際上在應用中基於很多原因,CPU的執行單元都沒有被充分使用。如果CPU不能正常讀取數據(匯流排/內存的瓶頸),其執行單元利用率會明顯下降。另外就是目前大多數執行線程缺乏ILP(Instruction-Level Parallelism,多種指令同時執行)支持。這些都造成了目前CPU的性能沒有得到全部的發揮。因此,Intel則採用另一個思路去提高CPU的性能,讓CPU可以同時執行多重線程,就能夠讓CPU發揮更大效率,即所謂「超線程(Hyper-Threading,簡稱「HT」)」技術。超線程技術就是利用特殊的硬體指令,把兩個邏輯內核模擬成兩個物理晶元,讓單個處理器都能使用線程級並行計算,進而兼容多線程操作系統和軟體,減少了CPU的閑置時間,提高的CPU的運行效率。 採用超線程及時可在同一時間里,應用程序可以使用晶元的不同部分。雖然單線程晶元每秒鍾能夠處理成千上萬條指令,但是在任一時刻只能夠對一條指令進行操作。而超線程技術可以使晶元同時進行多線程處理,使晶元性能得到提升。

⑦ select什麼時候比epoll效率高

一、問題引出 聯系區別

問題的引出,當需要讀兩個以上的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表示已超時。

⑧ C語言 epoll和多線程有什麼關系

1、epoll處理並發事件,多線程處理並發業務。
2、poll是Linux內核為處理大批量文件描述符而作了改進的poll,是Linux下多路復用IO介面select/poll的增強版本,它能顯著提高程序在大量並發連接中只有少量活躍的情況下的系統CPU利用率。另一點原因就是獲取事件的時候,它無須遍歷整個被偵聽的描述符集,只要遍歷那些被內核IO事件非同步喚醒而加入Ready隊列的描述符集合就行了。epoll除了提供select/poll那種IO事件的水平觸發(Level
Triggered)外,還提供了邊緣觸發(Edge
Triggered),這就使得用戶空間程序有可能緩存IO狀態,減少epoll_wait/epoll_pwait的調用,提高應用程序效率。

⑨ 求助,多線程+多個epoll

1、epoll處理並發事件,多線程處理並發業務。
2、poll是Linux內核為處理大批量文件描述符而作了改進的poll,是Linux下多路復用IO介面select/poll的增強版本,它能顯著提高程序在大量並發連接中只有少量活躍的情況下的系統CPU利用率。另一點原因就是獲取事件的時候,它無須遍歷整個被偵聽的描述符集,只要遍歷那些被內核IO事件非同步喚醒而加入Ready隊列的描述符集合就行了。epoll除了提供select/poll那種IO事件的水平觸發(Level Triggered)外,還提供了邊緣觸發(Edge Triggered),這就使得用戶空間程序有可能緩存IO狀態,減少epoll_wait/epoll_pwait的調用,提高應用程序效率。

閱讀全文

與伺服器多線程epoll效率提升相關的資料

熱點內容
前置桶過濾不幹凈 瀏覽:408
怎麼清洗上過濾棉 瀏覽:16
南山區污水改造工程 瀏覽:818
ro反滲透純水機好處 瀏覽:709
泰州反滲透凈水設備 瀏覽:268
馬桶會流水進入到凈水機怎麼辦 瀏覽:217
椰子EDI 瀏覽:550
飲水機熱水邊滴水怎麼回事 瀏覽:945
空氣濾芯聲音大是什麼原因 瀏覽:924
軋鋼廠污水處理 瀏覽:606
樹脂補牙吃了怎麼辦 瀏覽:139
廚房用什麼樣的家用凈水器好 瀏覽:138
摩托車空氣濾芯怎麼分辨 瀏覽:419
易開得怎麼打開清洗濾芯 瀏覽:736
反滲透飲水機電路工作原理 瀏覽:191
什麼叫沖洗凈水器 瀏覽:753
污水處理協議樣本 瀏覽:537
沈陽反滲透膜 瀏覽:821
納米環氧樹脂膠囊 瀏覽:701
怎樣自製污水池填料 瀏覽:386