EPOLL的理解和深入分析(轉(zhuǎn))

原文鏈接: https://blog.csdn.net/apacat/article/details/51375950

搞Linux 服務(wù)器開發(fā)的人肯定了解 select粱胜、poll另萤、epoll予弧,他們都是基于事件驅(qū)動的IO多路復(fù)用技術(shù)月匣,而他們之間的區(qū)別網(wǎng)上已經(jīng)有很多的文章了历筝,大家可以去詳細的閱讀,我在這里主要想寫寫我對epoll的底層實現(xiàn)的理解傻昙。

首先還是先說說 select闺骚、poll相比與epoll來說他們效率低下的原因吧:

select、poll妆档、epoll是Linux平臺下的IO多路復(fù)用技術(shù)僻爽,適合用來管理大量的文件描述符,但是這些系統(tǒng)調(diào)用本身是阻塞的贾惦,而他們管理的socket描述符其實是可以阻塞胸梆,也可以非阻塞的,但是大部分情況下設(shè)置為非阻塞的要更好一些须板,效率會更高一些碰镜。因此,他們并不是真正的異步IO逼纸。是偽異步的洋措。

1、select

首先杰刽,select的缺點1:是select管理的描述符的數(shù)量在不重新編譯內(nèi)核的情況下是一個固定的值:1024,當(dāng)然王滤,重新編譯了Linux內(nèi)核之后贺嫂,這個數(shù)值可以繼續(xù)增大到用戶的需求,但是這是相對來說比較麻煩的一件事雁乡。

其次第喳。select的缺點2:是select對于socket描述符的管理方式,因為Linux內(nèi)核對select的實現(xiàn)方式為每次返回前都要對所有的描述符進行一遍遍歷踱稍,然后將有事件發(fā)生的socket描述符放到描述符集合里曲饱,然后將這個描述符集合返回悠抹。這種情況對于描述符的數(shù)量不是很大的時候還是可以的,但是當(dāng)描述符達到數(shù)十萬扩淀,甚至上百萬的時候楔敌,select的效率就會急劇的降低,因為這樣的輪詢機制會造成大量的浪費和資源開銷驻谆。因為每一次的輪詢都要將這些所有的socket描述符從用戶態(tài)拷貝到內(nèi)核態(tài)卵凑,在內(nèi)核態(tài),進行輪詢胜臊,查看是否有事件發(fā)生勺卢,這是select的底層需要做的。而這些拷貝完全是可以避免的象对。

2黑忱、poll

poll的實現(xiàn)機制和select是一樣的,也是采用輪詢機制來查看有事件發(fā)生的socket描述符勒魔,所以效率也是很低甫煞,但是poll對select有一項改進就是能夠監(jiān)視的描述符是任意大小的而不是局限在一個較小的數(shù)值上(當(dāng)然這個描述符的大小也是需要操作系統(tǒng)來支持的)。

綜上:在總結(jié)一下沥邻,select與poll的實現(xiàn)機制基本是一樣的危虱,只不過函數(shù)不同,參數(shù)不同唐全,但是基本流程是相同的埃跷;

1、復(fù)制用戶數(shù)據(jù)到內(nèi)核空間

2邮利、估計超時時間

3弥雹、遍歷每個文件并調(diào)用f_op->poll()取得文件狀態(tài)

4、遍歷完成檢查狀態(tài)

如果有就緒的文件(描述符對應(yīng)的還是文件延届,這里就當(dāng)成是描述符就可以)則跳轉(zhuǎn)到5剪勿,

如果有信號產(chǎn)生則重新啟動poll或者select

否則掛起進程并等待超時或喚醒超時或再次遍歷每個文件的狀態(tài)

5、將所有文件的就緒狀態(tài)復(fù)制到用戶空間

6方庭、清理申請的資源

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

3厕吉、epoll

epoll改進了select的兩個缺點,使用了三個數(shù)據(jù)結(jié)構(gòu)從而能夠在管理大量的描述符的情況下械念,對系統(tǒng)資源的使用并沒有急劇的增加头朱,而只是對內(nèi)存的使用有所增加(畢竟存儲大量的描述符的數(shù)據(jù)結(jié)構(gòu)會占用大量內(nèi)存)。

epoll在實現(xiàn)上的三個核心點是:1龄减、mmap项钮,2、紅黑樹,3烁巫、rdlist(就緒描述符鏈表)接下來一一解釋這三個并且解釋為什么會高效署隘;

1、mmap是共享內(nèi)存亚隙,用戶進程和內(nèi)核有一段地址(虛擬存儲器地址)映射到了同一塊物理地址上磁餐,這樣當(dāng)內(nèi)核要對描述符上的事件進行檢查的時候就不用來回的拷貝了。


三恃鞋、共享內(nèi)存

這點實際上涉及到epoll的具體實現(xiàn)了崖媚。內(nèi)核/用戶空間 內(nèi)存拷貝問題,如何讓內(nèi)核把FD消息通知給用戶空間呢恤浪?

在這個問題上select采取了內(nèi)存拷貝方法畅哑。Poll也是么?應(yīng)該是水由,poll和select基本無區(qū)別荠呐?(肯定多少還有點區(qū)別,只是這些缺點是相同的)

既然是內(nèi)存拷貝砂客,因為也要拷貝啊泥张,還是慢!

對于poll來說需要將用戶傳入的 pollfd 數(shù)組拷貝到內(nèi)核空間鞠值,因為拷貝操作和數(shù)組長度相關(guān)媚创,時間上這是一個O(n)操作,當(dāng)事件發(fā)生彤恶,poll返回將獲得的數(shù)據(jù)傳送到用戶空間并執(zhí)行釋放內(nèi)存和剝離等待隊列等善后工作钞钙,向用戶空間拷貝數(shù)據(jù)與剝離等待隊列等操作的的時間復(fù)雜度同樣是O(n)。

而epoll是共享內(nèi)存声离,拷貝都不用,相對來說應(yīng)該會更快芒炼。epoll是通過內(nèi)核與用戶空間mmap同一塊內(nèi)存實現(xiàn)的。

mmap是什么

mmap操作提供了一種機制术徊,讓用戶程序直接訪問設(shè)備內(nèi)存本刽,這種機制,相比較在用戶空間內(nèi)核空間互相拷貝數(shù)據(jù)赠涮,效率更高子寓。在要求高性能的應(yīng)用中比較常用。mmap映射內(nèi)存必須是頁面大小的整數(shù)倍笋除,面向流的設(shè)備不能進行mmap别瞭,mmap的實現(xiàn)和硬件有關(guān)。

(涉及到內(nèi)核和用戶空間的概念株憾,共享內(nèi)存有沒有安全隱患?)


2、紅黑樹是用來存儲這些描述符的嗤瞎,因為紅黑樹的特性墙歪,就是良好的插入,查找贝奇,刪除性能O(lgN)虹菲。

 當(dāng)內(nèi)核初始化epoll的時候(當(dāng)調(diào)用epoll_create的時候內(nèi)核也是個epoll描述符創(chuàng)建了一個文件,畢竟在Linux中一切都是文件掉瞳,而epoll面對的是一個特殊的文件毕源,和普通文件不同),會開辟出一塊內(nèi)核高速cache區(qū)陕习,這塊區(qū)域用來存儲我們要監(jiān)管的所有的socket描述符霎褐,當(dāng)然在這里面存儲一定有一個數(shù)據(jù)結(jié)構(gòu),這就是紅黑樹该镣,由于紅黑樹的接近平衡的查找冻璃,插入,刪除能力损合,在這里顯著的提高了對描述符的管理省艳。

3、rdlist 就緒描述符鏈表這是一個雙鏈表嫁审,epoll_wait()函數(shù)返回的也是這個就緒鏈表跋炕。

 當(dāng)內(nèi)核創(chuàng)建了紅黑樹之后,同時也會建立一個雙向鏈表rdlist律适,用于存儲準備就緒的描述符辐烂,當(dāng)調(diào)用epoll_wait的時候在timeout時間內(nèi),只是簡單的去管理這個rdlist中是否有數(shù)據(jù)擦耀,如果沒有則睡眠至超時棉圈,如果有數(shù)據(jù)則立即返回并將鏈表中的數(shù)據(jù)賦值到events數(shù)組中。這樣就能夠高效的管理就緒的描述符眷蜓,而不用去輪詢所有的描述符分瘾。所以當(dāng)管理的描述符很多但是就緒的描述符數(shù)量很少的情況下如果用select來實現(xiàn)的話效率可想而知,很低吁系,但是epoll的話確實是非常適合這個時候使用德召。

  對與rdlist的維護:當(dāng)執(zhí)行epoll_ctl時除了把socket描述符放入到紅黑樹中之外,還會給內(nèi)核中斷處理程序注冊一個回調(diào)函數(shù)汽纤,告訴內(nèi)核上岗,當(dāng)這個描述符上有事件到達(或者說中斷了)的時候就調(diào)用這個回調(diào)函數(shù)。這個回調(diào)函數(shù)的作用就是將描述符放入到rdlist中蕴坪,所以當(dāng)一個socket上的數(shù)據(jù)到達的時候內(nèi)核就會把網(wǎng)卡上的數(shù)據(jù)復(fù)制到內(nèi)核肴掷,然后把socket描述符插入就緒鏈表rdlist中敬锐。

補充:epoll的工作模式ET和LT

都知道epoll有兩個工作模式,ET和LT呆瞻,其中ET模式是高速模式台夺,叫做邊緣觸發(fā)模式,LT模式是默認模式痴脾,叫做水平觸發(fā)模式颤介。

這兩種工作模式的區(qū)別在于:

當(dāng)工作在ET模式下,如果一個描述符上有數(shù)據(jù)到達赞赖,然后讀取這個描述符上的數(shù)據(jù)如果沒有將數(shù)據(jù)全部讀完的話滚朵,當(dāng)下次epoll_wait返回的時候這個描述符里的數(shù)據(jù)就再也讀取不到了,因為這個描述符不會再次觸發(fā)返回前域,也就沒法去讀取辕近,所以對于這種模式下對一個描述符的數(shù)據(jù)的正確讀取方式是用一個死循環(huán)一直讀,讀到么有數(shù)據(jù)可讀的情況下才可以認為是讀取結(jié)束话侄。

而工作在LT模式下亏推,這種情況就不會發(fā)生,如果對一個描述符的數(shù)據(jù)沒有讀取完成年堆,那么下次當(dāng)epoll_wait返回的時候會繼續(xù)觸發(fā)吞杭,也就可以繼續(xù)獲取到這個描述符,從而能夠接著讀变丧。

那么這兩種模式的實現(xiàn)方式是什么樣的?

基于以上的數(shù)據(jù)結(jié)構(gòu)是怎么實現(xiàn)這種工作模式的呢芽狗?

實現(xiàn)原理:當(dāng)一個socket描述符的中斷事件發(fā)生,內(nèi)核會將數(shù)據(jù)從網(wǎng)卡復(fù)制到內(nèi)核痒蓬,同時將socket描述符插入到rdlist中童擎,此時如果調(diào)用了epoll_wait會把rdlist中的就緒的socekt描述符復(fù)制到用戶空間,然后清理掉這個rdlist中的數(shù)據(jù)攻晒,最后epoll_wait還會再次檢查這些socket描述符顾复,如果是工作在LT模式下,并且這些socket描述符上還有數(shù)據(jù)沒有讀取完成鲁捏,那么L就會再次把沒有讀完的socket描述符放入到rdlist中芯砸,所以再次調(diào)用epoll_wait的時候是會再次觸發(fā)的,而ET模式是不會這么干的给梅。

ET模式在物理實現(xiàn)上是基于電平的高低變化來工作的假丧,就是從高電平變成低電平,或者從低電平變成高電平的這個上升沿或者下降沿才會觸發(fā)动羽,也就是狀態(tài)變化導(dǎo)致觸發(fā)包帚,而當(dāng)一個描述符上數(shù)據(jù)未讀完的時候這個狀態(tài)是不會發(fā)生變化的,所以觸發(fā)不了运吓,LT模式是在只有出現(xiàn)高電平的時候才會觸發(fā)渴邦。

高電平和低電平:

LT水平觸發(fā):

EPOLLIN的觸發(fā)事件:當(dāng)輸入緩沖區(qū)為空-->低電平疯趟,當(dāng)輸入緩沖區(qū)不為空-->高電平

高電平的時候觸發(fā)EPOLLIN事件,如果沒有把緩沖區(qū)的數(shù)據(jù)讀取完几莽,下次還會觸發(fā)的迅办,因為始終是高電平

EPOLLOUT的觸發(fā)事件:當(dāng)發(fā)送緩沖區(qū)滿-->低電平,當(dāng)發(fā)送緩沖區(qū)不滿-->高電平

高電平的時候觸發(fā)EPOLLOUT事件章蚣,所以在一開始的時候不要關(guān)注EPOLLOUT時間,因為發(fā)送緩沖區(qū)是不滿的所以會導(dǎo)致CPU忙等待姨夹,每次都觸發(fā)纤垂。什么時候關(guān)注EPOLLOUT事件呢? 當(dāng)write的時候沒有寫完全,因為發(fā)送緩沖區(qū)滿了磷账,這個時候才關(guān)注EPOLLOUT事件直到下次把所有數(shù)據(jù)都發(fā)送完畢了峭沦,才取消EPOLLOUT事件

ET邊緣觸發(fā):

EPOLLIN事件發(fā)生的條件:

有數(shù)據(jù)到來(輸入緩沖區(qū)初始為空,為低電平逃糟,有數(shù)據(jù)到來變成了高電平)

EPOLLout事件發(fā)生的條件:

內(nèi)核發(fā)送緩沖區(qū)不滿(當(dāng)發(fā)送緩沖區(qū)出現(xiàn)滿之后為低電平吼鱼,然后內(nèi)核發(fā)送出去了部分數(shù)據(jù)后變成了不滿,也就是高電平)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末绰咽,一起剝皮案震驚了整個濱河市菇肃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌取募,老刑警劉巖琐谤,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異玩敏,居然都是意外死亡斗忌,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門旺聚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來织阳,“玉大人,你說我怎么就攤上這事砰粹∵蠖悖” “怎么了?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵伸眶,是天一觀的道長惊窖。 經(jīng)常有香客問我,道長厘贼,這世上最難降的妖魔是什么界酒? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮嘴秸,結(jié)果婚禮上毁欣,老公的妹妹穿的比我還像新娘庇谆。我一直安慰自己,他們只是感情好凭疮,可當(dāng)我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布饭耳。 她就那樣靜靜地躺著,像睡著了一般执解。 火紅的嫁衣襯著肌膚如雪寞肖。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天衰腌,我揣著相機與錄音新蟆,去河邊找鬼。 笑死右蕊,一個胖子當(dāng)著我的面吹牛琼稻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播饶囚,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼帕翻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了萝风?” 一聲冷哼從身側(cè)響起嘀掸,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎闹丐,沒想到半個月后横殴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡卿拴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年衫仑,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片堕花。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡文狱,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缘挽,到底是詐尸還是另有隱情瞄崇,我是刑警寧澤,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布壕曼,位于F島的核電站苏研,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏腮郊。R本人自食惡果不足惜摹蘑,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望轧飞。 院中可真熱鬧衅鹿,春花似錦撒踪、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至泵三,卻和暖如春耕捞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背切黔。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工砸脊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人纬霞。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像驱显,于是被迫代替她去往敵國和親诗芜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,562評論 2 349

推薦閱讀更多精彩內(nèi)容