Node.js的心臟-epoll

1、Node.js和epoll

? ? 我們都知道Node.js是異步的,那么Node.js為什么會(huì)是異步的呢?這是因?yàn)镹ode.js使用了LIBUV做為它的跨平臺(tái)抽象層。具體請(qǐng)看nodejs運(yùn)行機(jī)制

2、select/poll/epoll

? ? select、poll、epoll是Linux平臺(tái)下的IO多路復(fù)用機(jī)制,用來(lái)管理大量的文件描述符。但是select/poll相對(duì)于epoll來(lái)說(shuō)效率是低下的。

select

? ? ? 1、linux內(nèi)核在select的每次返回前都要對(duì)所有的描述符循環(huán)遍歷,將有事件發(fā)生的文件描述符放在一個(gè)集合里返回。在描述符不多的時(shí)候?qū)π阅苡绊懖淮?,但是?dāng)描述符達(dá)到數(shù)十萬(wàn)甚至更多的時(shí)候,這種處理方式造成大量的浪費(fèi)和資源開(kāi)銷(xiāo),select的效率會(huì)急劇下降。這是因?yàn)槊看蝧elect的時(shí)候,會(huì)將所有的文件描述符從用戶(hù)態(tài)拷貝的內(nèi)核態(tài),在內(nèi)核態(tài)進(jìn)行循環(huán),查看是否有事件發(fā)生。2、select默認(rèn)的管理的最大文件描述符是1024個(gè),當(dāng)然可以對(duì)linux內(nèi)核從新編譯來(lái)改變這個(gè)限制。

poll

? ? 原理和select相似也是使用循環(huán)遍歷的方式管理文件描述符,不同的是管理的文件最大文件描述符的數(shù)量沒(méi)有限制(根據(jù)系統(tǒng)限制來(lái)定)。

epoll

下文講解epoll實(shí)現(xiàn)原理

3、epoll實(shí)現(xiàn)原理

? ??epoll改進(jìn)了select的兩個(gè)缺點(diǎn),從而能夠在管理大量的描述符的情況下,對(duì)系統(tǒng)資源的使用并沒(méi)有急劇的增加,而只是對(duì)內(nèi)存的使用有所增加(畢竟存儲(chǔ)大量的描述符的數(shù)據(jù)結(jié)構(gòu)會(huì)占用大量?jī)?nèi)存)。epoll在實(shí)現(xiàn)上的三個(gè)核心點(diǎn)是:1、mmap,2、紅黑樹(shù),3、rdlist(就緒描述符鏈表)接下來(lái)一一解釋這三個(gè)并且解釋為什么會(huì)高效。

mmap

????mmap是共享內(nèi)存,用戶(hù)進(jìn)程和內(nèi)核有一段地址(虛擬存儲(chǔ)器地址)映射到了同一塊物理地址上,這樣當(dāng)內(nèi)核要對(duì)描述符上的事件進(jìn)行檢查的時(shí)候就不用來(lái)回的拷貝了。? ?

紅黑樹(shù)

????紅黑樹(shù)是用來(lái)存儲(chǔ)這些描述符的。當(dāng)內(nèi)核初始化epoll的時(shí)候(當(dāng)調(diào)用epoll_create的時(shí)候內(nèi)核也是個(gè)epoll描述符創(chuàng)建了一個(gè)文件,畢竟在Linux中一切都是文件,而epoll面對(duì)的是一個(gè)特殊的文件,和普通文件不同),會(huì)開(kāi)辟出一塊內(nèi)核緩沖區(qū),這塊區(qū)域用來(lái)存儲(chǔ)我們要監(jiān)管的所有的socket描述符,當(dāng)然在這里面存儲(chǔ)有一個(gè)數(shù)據(jù)結(jié)構(gòu),這就是紅黑樹(shù),由于紅黑樹(shù)的接近平衡的查找,插入,刪除能力,在這里顯著的提高了對(duì)描述符的管理。

rdlist

????????rdlist就緒描述符鏈表這是一個(gè)雙鏈表,epoll_wait()函數(shù)返回的也是這個(gè)就緒鏈表。當(dāng)內(nèi)核創(chuàng)建了紅黑樹(shù)之后,同時(shí)也會(huì)建立一個(gè)雙向鏈表rdlist,用于存儲(chǔ)準(zhǔn)備就緒的描述符,當(dāng)調(diào)用epoll_wait的時(shí)候在timeout時(shí)間內(nèi),只是簡(jiǎn)單的去管理這個(gè)rdlist中是否有數(shù)據(jù),如果沒(méi)有則睡眠至超時(shí),如果有數(shù)據(jù)則立即返回并將鏈表中的數(shù)據(jù)賦值到events數(shù)組中。這樣就能夠高效的管理就緒的描述符,而不用去輪詢(xún)所有的描述符。

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

Epoll的兩種模式:

????? 1.?水平觸發(fā)(LT):使用此種模式,當(dāng)數(shù)據(jù)可讀的時(shí)候,epoll_wait()將會(huì)一直返回就緒事件。如果你沒(méi)有處理完全部數(shù)據(jù),并且再次在該epoll實(shí)例上調(diào)用epoll_wait()才監(jiān)聽(tīng)描述符的時(shí)候,它將會(huì)再次返回就緒事件,因?yàn)橛袛?shù)據(jù)可讀。

????? 2.?邊緣觸發(fā)(ET):使用此種模式,只能獲取一次就緒通知,如果沒(méi)有處理完全部數(shù)據(jù),并且再次調(diào)用epoll_wait()的時(shí)候,它將會(huì)阻塞,因?yàn)榫途w事件已經(jīng)釋放出來(lái)了。

? ? ? ? ET的效能更高,但是對(duì)程序員的要求也更高。在ET模式下,我們必須一次干凈而徹底地處理完所有事件。

4、epoll實(shí)現(xiàn)

epoll的linux實(shí)現(xiàn)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • epoll概述 epoll是linux中IO多路復(fù)用的一種機(jī)制,I/O多路復(fù)用就是通過(guò)一種機(jī)制,一個(gè)進(jìn)程可以監(jiān)視多...
    發(fā)仔很忙閱讀 11,082評(píng)論 4 35
  • 前言 這篇文章讀不懂的沒(méi)關(guān)系,可以先收藏一下。筆者準(zhǔn)備介紹完epoll和NIO等知識(shí)點(diǎn),然后寫(xiě)一篇Java網(wǎng)絡(luò)IO...
    全菜工程師小輝閱讀 24,743評(píng)論 1 37
  • 作者:靜海聽(tīng)風(fēng)鏈接:https://www.zhihu.com/question/20122137/answer/...
    C_A_dogN閱讀 2,952評(píng)論 0 4
  • 在看kafka的生產(chǎn)者基于NIO構(gòu)建網(wǎng)絡(luò)通信層NetworkClient的時(shí)候,發(fā)覺(jué)自己對(duì)網(wǎng)絡(luò)通信的相關(guān)知識(shí)(同步...
    紹圣閱讀 1,095評(píng)論 0 1
  • 一、為什么epoll這么快: epoll是多路復(fù)用IO(I/O Multiplexing)中的一種方式,但是僅用于...
    hcci閱讀 1,474評(píng)論 0 9

友情鏈接更多精彩內(nèi)容