溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

三種多路復用IO實現方式:select,poll,epoll的區別

發布時間:2020-07-13 15:15:23 來源:網絡 閱讀:2757 作者:小止1995 欄目:編程語言

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

此時需知道兩個概念:

所謂阻塞方式block,顧名思義,就是進程或是線程執行到這些函數時必須等待某個事件的發生,如果事件沒有發生,進程或線程就被阻塞,函數不能立即返回。

所謂非阻塞方式non-block,就是進程或線程執行此函數時不必非要等待事件的發生,一旦執行肯定返回,以返回值的不同來反映函數的執行情況,如果事件發生則與阻塞方式相同,若事件沒有發生,則返回一個代碼來告知事件未發生,而進程或線程繼續執行,所以效率較高。

一.select()的機制中提供一fd_set的數據結構,實際上是一long類型的數組, 每一個數組元素都能與一打開的文件句柄(不管是Socket句柄,還是其他 文件或命名管道或設備句柄)建立聯系,建立聯系的工作由程序員完成, 當調用select()時,由內核根據IO狀態修改fd_set的內容,由此來通知執行了select()的進程哪一Socket或文件可讀或可寫。主要用于Socket通信當中。

select使用:它能夠監視我們需要監視的文件描述符的變化情況——讀寫或是異常。準備就緒的描述符數,若超時則返回0,若出錯則返回-1。

1.如果一個發現I/O有輸入,讀取的過程中,另外一個也有了輸入,這時候不會產生任何反應.這就需要你的程序語句去用到select函數的時候才知道有數據輸入。

2.程序去select的時候,如果沒有數據輸入,程序會一直等待(阻塞時),直到有數據為止,也就是程序中無需循環和sleep。

#include <sys/types.h>

#include <sys/times.h>

#include <sys/select.h>

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

函數返回結果:當readfds或writefds中映象的文件可讀或可寫或超時,本次select()就結束返回。程序員利用一組系統提供的宏在select()結束時便可判斷哪一文件可讀或可寫,對Socket編程特別有用的就是readfds。

注:不同的timeval設置使select()表現出超時結束、無超時阻塞和輪詢三種特性(timeval可精確至百萬分之一秒)。

select詳細執行步驟:

三種多路復用IO實現方式:select,poll,epoll的區別

(1)使用copy_from_user從用戶空間拷貝fd_set到內核空間

(2)注冊回調函數__pollwait

(3)遍歷所有fd,調用其對應的poll方法(對于socket,這個poll方法是sock_poll,sock_poll根據情況會調用到tcp_poll,udp_poll或者datagram_poll)

(4)以tcp_poll為例,其核心實現就是__pollwait,也就是上面注冊的回調函數。

(5)__pollwait的主要工作就是把current(當前進程)掛到設備的等待隊列中,不同的設備有不同的等待隊列,對于tcp_poll來說,其等待隊列是sk->sk_sleep(注意把進程掛到等待隊列中并不代表進程已經睡眠了)。在設備收到一條消息(網絡設備)或填寫完文件數據(磁盤設備)后,會喚醒設備等待隊列上睡眠的進程,這時current便被喚醒了。

(6)poll方法返回時會返回一個描述讀寫操作是否就緒的mask掩碼,根據這個mask掩碼給fd_set賦值。

(7)如果遍歷完所有的fd,還沒有返回一個可讀寫的mask掩碼,則會調用schedule_timeout是調用select的進程(也就是current)進入睡眠。當設備驅動發生自身資源可讀寫后,會喚醒其等待隊列上睡眠的進程。如果超過一定的超時時間(schedule_timeout指定),還是沒人喚醒,則調用select的進程會重新被喚醒獲得CPU,進而重新遍歷fd,判斷有沒有就緒的fd。

(8)把fd_set從內核空間拷貝到用戶空間。

從以上工作流程可得到select特點:

a.所監視的每種事件描述符個數有上限;

printf("%d\n",sizeof(fd_set));

我的linux系統所能關心事件應為128字節*8=1024個描述符

三種多路復用IO實現方式:select,poll,epoll的區別

b.調用前后輪詢;

使用select函數,必須使用輔助數組保存關心的描述符,因為select函數中描述符集是輸入輸出型參數,故在調用前應輪詢數組重置描述符集,調用后得輪詢描述符集判斷關心事件是否就緒。

c.系統與用戶數據拷貝:使用copy_from_user從用戶空間拷貝fd_set到內核空間。

d.調用前需重置(描述符集是輸入輸出型參數)。

二.poll:

poll的實現和select非常相似,只是描述fd集合的方式不同,poll使用pollfd結構而不是select的fd_set結構,其他的都差不多。

#include <poll.h>

int poll(struct pollfd fds[], nfds_t nfds, int timeout);

監視描述符事件選項:

三種多路復用IO實現方式:select,poll,epoll的區別

fds:是一個struct pollfd結構類型的數組,用于存放需要檢測其狀態的Socket描述符;每當調用這個函數之后,系統不會清空這個數組,操作起來比較方便;特別是對于socket連接比較多的情況下,在一定程度上可以提高處理的效率;這一點與select()函數不同,調用select()函數之后,select()函數會清空它所檢測的socket描述符集合,導致每次調用select()之前都必須把socket描述符重新加入到待檢測的集合中;因此,select()函數適合于只檢測一個socket描述符的情況,而poll()函數適合于大量socket描述符的情況;與select()十分相似,當返回正值時,代表滿足響應事件的文件描述符的個數,如果返回0則代表在規定時間內沒有事件發生。如發現返回為負則應該立即查看 errno,因為這代表有錯誤發生。

注:如果沒有事件發生,revents會被清空。

poll特點:

  1. 監視描述符個數無上限;

最大描述符+1,個數由fds數組決定。

2.監視事件與返回后事件狀態反生分離,調用前后不需重置。

3.調用后輪詢檢測監視事件是否發生。

4.系統與用戶數據拷貝:使用copy_from_user從用戶空間拷貝fds到內核空間

三.epoll.

epoll是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和select和poll的調用接口上的不同。

select和poll都只提供了一個函數——select或者poll函數。而epoll提供了三個函數,epoll_create,epoll_ctl和epoll_wait,epoll_create是創建一個epoll句柄;epoll_ctl是注冊要監聽的事件類型;epoll_wait則是等待事件的產生。

2.使用mmap加速內核與用戶空間的消息傳遞。

對于select和poll函數的系統與內核每次調用時的數據拷貝:epoll是通過內核與用戶空間mmap同一塊內存實現的,在epoll_ctl函數中:每次注冊新的事件到epoll句柄中時(在epoll_ctl中指定EPOLL_CTL_ADD),會把所有的fd拷貝進內核,而不是在epoll_wait的時候重復拷貝。epoll保證了每個fd在整個過程中只會拷貝一次。

3.調用后不需輪詢判斷描述符事件是否就緒。

對于select和poll函數每次調用后輪詢檢測事件是否發生:epoll的解決方案不像select或poll一樣每次都把current輪流加入fd對應的設備等待隊列中,而只在epoll_ctl時把current掛一遍(這一遍必不可少)并為每個fd指定一個回調函數,當設備就緒,喚醒等待隊列上的等待者時,就會調用這個回調函數,而這個回調函數會把就緒的fd加入一個就緒鏈表)。epoll_wait的工作實際上就是在這個就緒鏈表中查看有沒有就緒的fd(利用schedule_timeout()實現睡一會,判斷一會的效果)。

4.監視描述符沒有個數上限。

epoll沒有這個限制,它所支持的FD上限是最大可以打開文件的數目,這個數字一般遠大于2048,注:在1GB內存的機器上大約是10萬左右,具體數目可以cat /proc/sys/fs/file-max察看,一般來說這個數目和系統內存關系很大。

5.IO效率不隨FD數目增加而線性下降。

傳統的select/poll另一個致命弱點就是當你擁有一個很大的socket集合,不過由于網絡延時,任一時間只有部分的socket是“活躍”的,但是select/poll每次調用都會線性掃描全部的集合,導致效率呈現線性下降。但是epoll不存在這個問題,它只會對“活躍”的socket進行操作---這是因為在內核實現中epoll是根據每個fd上面的callback函數實現的。只有“活躍”的socket才會主動的去調用 callback函數,其他idle狀態socket則不會。

拓展:系統維護一顆紅黑樹(平衡搜索二叉樹:穩定)存儲監視描述符,和一張鏈表存儲就緒的描述符。當每次注冊或修改,刪除新的文件描述符到epoll句柄中時,就會增加一個描述符到這課紅黑樹中(增刪改查簡單),當返回時檢測鏈表上是否有節點,有節點則拷貝到用戶傳給它的那個描述符數組中。

epoll對于select和poll相比,顯著優點是:

(1)select,poll實現需要自己不斷輪詢所有fd集合,直到設備就緒,期間可能要睡眠和喚醒多次交替。而epoll其實也需要調用epoll_wait不斷輪詢就緒鏈表,期間也可能多次睡眠和喚醒交替,但是它是設備就緒時,調用回調函數,把就緒fd放入就緒鏈表中,并喚醒在epoll_wait中進入睡眠的進程。雖然都要睡眠和交替,但是select和poll在“醒著”的時候要遍歷整個fd集合,而epoll在“醒著”的時候只要判斷一下就緒鏈表是否為空就行了,這節省了大量的CPU時間。這就是回調機制帶來的性能提升。

(2)select,poll每次調用都要把fd集合從用戶態往內核態拷貝一次,并且要把current往設備等待隊列中掛一次,而epoll只要一次拷貝,而且把current往等待隊列上掛也只掛一次(在epoll_wait的開始,注意這里的等待隊列并不是設備等待隊列,只是一個epoll內部定義的等待隊列)。這也能節省不少的開銷。

總結:

select

  select能監控的描述符個數由內核中的FD_SETSIZE限制,僅為1024,這也是select最大的缺點,因   為現在的服務器并發量遠遠不止1024。即使能重新編譯內核改變FD_SETSIZE的值,但這并不能提高   select的性能。

  • 每次調用select都會線性掃描所有描述符的狀態,在select結束后,用戶也要線性掃描fd_set數組才知道哪些描述符準備就緒,等于說每次調用復雜度都是O(n)的,在并發量大的情況下,每次掃描都是相當耗時的,很有可能有未處理的連接等待超時。

  • 每次調用select都要在用戶空間和內核空間里進行內存復制fd描述符等信息。

poll

  • poll使用pollfd結構來存儲fd,突破了select中描述符數目的限制。

  • 與select的后兩點類似,poll仍然需要將pollfd數組拷貝到內核空間,之后依次掃描fd的狀態,整體復雜度依然是O(n)的,在并發量大的情況下服務器性能會快速下降。

epoll

  • epoll維護的描述符數目不受到限制,而且性能不會隨著描述符數目的增加而下降。

  • 服務器的特點是經常維護著大量連接,但其中某一時刻讀寫的操作符數量卻不多。epoll先通過epoll_ctl注冊一個描述符到內核中,并一直維護著而不像poll每次操作都將所有要監控的描述符傳遞給內核;在描述符讀寫就緒時,通過回掉函數將自己加入就緒隊列中,之后epoll_wait返回該就緒隊列。也就是說,epoll基本不做無用的操作,時間復雜度僅與活躍的客戶端數有關,而不會隨著描述符數目的增加而下降。

  • epoll在傳遞內核與用戶空間的消息時使用了內存共享,而不是內存拷貝,這也使得epoll的效率比poll和select更高。



三種多路復用IO實現方式:select,poll,epoll的區別

poll和epoll適用于關心描述符個數多的應用程序。其中epoll對于每次只有很少描述符就緒很有優勢(采用回調機制監測描述符就緒)。

綜上:epoll是上面三個函數中效率最高的。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女