新聞中心
在Linux系統(tǒng)中,I/O操作是一個非常重要的部分,這也是讓系統(tǒng)支持更高級的網(wǎng)絡(luò)應(yīng)用程序的重要因素之一。原始的Linux操作系統(tǒng)中,主要是使用select和poll等方法來實現(xiàn)I/O多路復(fù)用的。但是,在高負(fù)載情況下,這些方法會出現(xiàn)效率較低的瓶頸。因此,Linux內(nèi)核開發(fā)人員就在2.6版本中引入了epoll機(jī)制,來解決這個問題。

專注于為中小企業(yè)提供成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)武定免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了千余家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
epoll機(jī)制是Linux內(nèi)核提供的一種高效的I/O多路復(fù)用機(jī)制。相較于select和poll等方法,在高負(fù)載情況下,epoll可以更有效地處理多個客戶端請求,提高系統(tǒng)響應(yīng)速度和處理能力。那么,epoll是如何實現(xiàn)這樣高效的多路復(fù)用呢?
一、epoll基本原理
epoll機(jī)制主要借助了Linux內(nèi)核中的“事件通知機(jī)制”。這個機(jī)制是通過一個雙向鏈表和一個紅黑樹來實現(xiàn)的。每當(dāng)一個文件描述符上發(fā)生一個事件時,它就會被添加到雙向鏈表中的某個位置上。而紅黑樹的作用,則是快速地查找當(dāng)前發(fā)生事件的文件描述符。
在使用epoll時,應(yīng)用程序會首先創(chuàng)建一個epoll實例,并用epoll_create函數(shù)獲取一個描述符。接著,在epoll實例中注冊一些感興趣的文件描述符(讀、寫、異常等),這些事件被注冊之后,內(nèi)核就會將這些文件描述符添加到雙向鏈表和紅黑樹中。如果這些文件描述符上出現(xiàn)了感興趣的事件,那么內(nèi)核就會將它們添加到一個就緒事件鏈表中,并通過epoll_wt或類似的函數(shù)通知應(yīng)用程序。
二、epoll與select、poll的比較
1. 其他方法的缺陷
在傳統(tǒng)的select和poll等方法中,應(yīng)用程序需要將所有需要監(jiān)聽的文件描述符都加到輪詢列表中。而在輪詢列表中,每個文件描述符都要被遍歷一遍,來檢查它是否產(chǎn)生了需要監(jiān)聽的事件。這就會產(chǎn)生很多不必要的操作,浪費(fèi)了系統(tǒng)資源和CPU周期。
另外,select和poll等方法對于可讀、可寫和出現(xiàn)異常等事件的處理方式,也是比較粗略的。在這些方法中,每次事件被觸發(fā)時,整個列表中的所有文件描述符都必須被重新掃描一遍。這樣,就會產(chǎn)生很多無謂的內(nèi)存和CPU消耗。
2. epoll的優(yōu)點
與select和poll等傳統(tǒng)的I/O多路復(fù)用方法相比,epoll有以下幾點優(yōu)勢:
(1)支持更多文件描述符
select和poll等方法都有一個缺陷,就是最多只能支持1024個文件描述符。如果要監(jiān)聽更多的文件描述符,就必須使用多個進(jìn)程進(jìn)行處理。而epoll則沒有這個限制,它可以同時監(jiān)視一百萬個文件描述符。
(2)IO效率更高
在select和poll等方法中,每個文件描述符的監(jiān)聽狀態(tài)都會被復(fù)制到內(nèi)核中去。而在epoll中,則只需要復(fù)制一次,因此I/O效率更高。
另外,在epoll中,內(nèi)核直接將監(jiān)聽狀態(tài)的文件描述符添加到了事件數(shù)組中,而不是輪詢列表中。當(dāng)有事件觸發(fā)時,只有真正產(chǎn)生事件的文件描述符會被回傳,減少了不必要的遍歷。
(3)更靈活的監(jiān)聽模式
在select和poll中,每個文件描述符只能同時被監(jiān)聽一種事件類型(可讀、可寫或異常)。而在epoll中,則可以同時監(jiān)聽不同類型的事件。
此外,在epoll中還可以使用ET模式進(jìn)行事件監(jiān)聽。ET模式是指邊緣觸發(fā)模式,當(dāng)事件產(chǎn)生時,內(nèi)核只會通知一次。而在LT模式中,則會在文件描述符上保持一個狀態(tài),直到它的事件被處理完畢。因此,ET模式的效率更高。
三、epoll實現(xiàn)原理分析
epoll的實現(xiàn)是比較復(fù)雜的,主要要穿插文件描述符的狀態(tài)處理、內(nèi)存管理、多線程等多個方面。但總體而言,它的實現(xiàn)原理可以分為以下幾個方面:
1. 狀態(tài)管理
在epoll機(jī)制中,每個文件描述符都會有一個內(nèi)部數(shù)據(jù)結(jié)構(gòu)。這個數(shù)據(jù)結(jié)構(gòu)中包含了文件描述符的當(dāng)前狀態(tài)、監(jiān)聽事件和回調(diào)函數(shù)等信息。所有的數(shù)據(jù)結(jié)構(gòu)和管理都是由內(nèi)核完成的。
每當(dāng)一個文件描述符上的事件被觸發(fā)時,相應(yīng)的數(shù)據(jù)結(jié)構(gòu)就會被更新。如果文件描述符上的事件被取消了,則相應(yīng)的事件處理器也會被刪除。這樣,內(nèi)核就可以根據(jù)當(dāng)前的事件狀態(tài),來更智能地處理I/O調(diào)度。
2. 內(nèi)存管理
在epoll中,所有內(nèi)存的處理都是交給內(nèi)核的。當(dāng)應(yīng)用程序使用epoll_create時,內(nèi)核會為epoll實例分配內(nèi)存,來存儲epoll所需要的所有信息。
在內(nèi)存分配過程中,盡量避免發(fā)生內(nèi)存泄漏或內(nèi)存損壞等問題,這樣可以更好地保證應(yīng)用程序的穩(wěn)定性。
3. 多線程處理
為了提高epoll的效率,內(nèi)核會使用多線程來加速事件處理。當(dāng)有事件產(chǎn)生時,內(nèi)核會先將它加入到一個就緒列表中,并通知正在等待事件的線程。當(dāng)線程獲取事件后,就可以快速地對事件進(jìn)行處理。
同時,在epoll中,需要盡可能地避免線程間的互相干擾。當(dāng)有多個線程同時訪問文件描述符上的事件時,需要使用互斥量、讀寫鎖等機(jī)制,來避免數(shù)據(jù)競爭和死鎖等問題。
四、
epoll機(jī)制是Linux內(nèi)核提供的一種高效的I/O多路復(fù)用機(jī)制。與select和poll等傳統(tǒng)方法相比,epoll具有更高的處理能力和更靈活的監(jiān)聽模式。在使用epoll時,應(yīng)用程序只需要將需要監(jiān)聽的文件描述符注冊到epoll實例中,在事件觸發(fā)時,內(nèi)核就可以根據(jù)當(dāng)前的事件狀態(tài),更智能地進(jìn)行I/O調(diào)度。
epoll機(jī)制為高負(fù)載的網(wǎng)絡(luò)應(yīng)用程序提供了更好的支持。然而,在使用epoll時,也需要注意一些問題,例如內(nèi)存管理、多線程處理和進(jìn)程調(diào)度等問題。只有通過對這些問題的深入了解和處理,才能更好地發(fā)揮epoll的優(yōu)勢,提高應(yīng)用程序的性能和穩(wěn)定性。
成都網(wǎng)站建設(shè)公司-創(chuàng)新互聯(lián),建站經(jīng)驗豐富以策略為先導(dǎo)10多年以來專注數(shù)字化網(wǎng)站建設(shè),提供企業(yè)網(wǎng)站建設(shè),高端網(wǎng)站設(shè)計,響應(yīng)式網(wǎng)站制作,設(shè)計師量身打造品牌風(fēng)格,熱線:028-86922220Node.js的心臟-epoll
我們都知道Node.js是異步的,那么Node.js為什么會是異步的呢?這是因為Node.js使用了LIBUV做為它的跨平臺抽象層。具體請看 nodejs運(yùn)行機(jī)制
select、poll、epoll是Linux平臺下的IO多路復(fù)用機(jī)制,用來管理大量的文件描述符。但是select/poll相對于epoll來說效率是低下的。
、linux內(nèi)核在select的每次返回前都要對所有的描述符 循環(huán)遍歷 ,將有事件發(fā)生的文件描述符放在一個里返回。在描述符不多的時候?qū)π阅苡绊懖淮螅钱?dāng)描述符達(dá)到數(shù)十萬甚至更多的時候,這種處理方式造成大量的浪費(fèi)和資源開銷,select的效率會急劇下降。這是因為每次select的時候,會將所有的文件描述符從用戶態(tài)拷貝的內(nèi)核態(tài),在內(nèi)核態(tài)進(jìn)行循環(huán),查看是否有事件發(fā)生。2、select默認(rèn)的管理的更大文件描述符是1024個,當(dāng)然可以對linux內(nèi)核從新編譯來改變這個限制。
原理和select相似也是使用循環(huán)遍歷的方式管理文件描述符,不同的是管理的文件更大文件描述符的數(shù)量沒有限制(根據(jù)系統(tǒng)限制來定)。
下文講解epoll實現(xiàn)原理
epoll改進(jìn)了select的兩個缺點,從而能夠在管理大量的描述符的情況下,對系統(tǒng)資源的使用并沒有急劇的增加,而只是對內(nèi)存的使用有所增加(畢竟存儲大量的描述符的數(shù)據(jù)結(jié)構(gòu)會占用大量內(nèi)存)。epoll在實現(xiàn)上的三個核心點是:1、mmap,2、紅黑樹,3、rdlist(就緒描述符鏈表)接下來一一解釋這三個并且解釋為什么會高效。
mmap是共享內(nèi)存,用戶進(jìn)程和內(nèi)核有一段地址(虛擬存儲器地址)映射到了同一塊物理地址上,這樣當(dāng)內(nèi)核要對描述符上的事件進(jìn)行檢查的時候就不用來回的拷貝了。
紅黑樹是用來存儲這些描述符的。當(dāng)內(nèi)核初始化epoll的時候(當(dāng)調(diào)用epoll_create的時候內(nèi)核也是個epoll描述符創(chuàng)建了一個文件,畢竟在Linux中一切都是文件,而epoll面對的是一個特殊的文件,和普通文件不同),會開辟出一塊內(nèi)核緩沖區(qū),這塊區(qū)域用來存儲我們要監(jiān)管的所有的socket描述符,當(dāng)然在這里面存儲有一個數(shù)據(jù)結(jié)構(gòu),這就是紅黑樹,由于紅黑樹的接近平衡的查找,插入,刪除能力,在這里顯著的提高了對描述符的管理。
rdlist就緒描述符鏈表這是一個雙鏈表,epoll_wait()函數(shù)返回的也是這個就緒鏈表。當(dāng)內(nèi)核創(chuàng)建了紅黑樹之后,同時也會建立一個雙向鏈表rdlist,用于存儲準(zhǔn)備就緒的描述符,當(dāng)調(diào)用epoll_wait的時候在timeout時間內(nèi),只是簡單的去管理這個rdlist中是否有數(shù)據(jù),如果沒有則睡眠至超時,如果有數(shù)據(jù)則立即返回并將鏈表中的數(shù)據(jù)賦值到events數(shù)組中。這樣就能夠高效的管理就緒的描述符,而不用去輪詢所有的描述符。
當(dāng)執(zhí)行epoll_ctl時除了把socket描述符放入到紅黑樹中之外,還會給內(nèi)核中斷處理程序注冊一個回調(diào)函數(shù),告訴內(nèi)核,當(dāng)這個描述符上有事件到達(dá)(或者說中斷了)的時候就調(diào)用這個回調(diào)函數(shù)。這個回調(diào)函數(shù)的作用就是將描述符放入到rdlist中,所以當(dāng)一個socket上的數(shù)據(jù)到達(dá)的時候內(nèi)核就會把網(wǎng)卡上的數(shù)據(jù)復(fù)制到內(nèi)核,然后把socket描述符插入就緒鏈表rdlist中。
Epoll的兩種模式:
. 水平觸發(fā)(LT):使用此種模式,當(dāng)數(shù)據(jù)可讀的時候,epoll_wait()將會一直返回就緒事件。如果你沒有處理完全部數(shù)據(jù),并且再次在該epoll實例上調(diào)用epoll_wait()才監(jiān)聽描述符的時候,它將會再次返回就緒事件,因為有數(shù)據(jù)可讀。
. 邊緣觸發(fā)(ET):使用此種模式,只能獲取一次就緒通知,如果沒有處理完全部數(shù)據(jù),并且再次調(diào)用epoll_wait()的時候,它將會阻塞,因為就緒事件已經(jīng)釋放出來了。
ET的效能更高,但是對程序員的要求也更高。在ET模式下,我們必須一次干凈而徹底地處理完所有事件。
epoll的linux實現(xiàn)
linux手冊翻譯——epoll(7)
epoll — I/O 事件通知機(jī)制
epoll API與poll具有相同功能:監(jiān)視多個文件描述符,以查看這些文件描述符中任何一個上可以進(jìn)行特定的I/O操作,如是否可讀/可寫。epoll API可以使用edge-triggered和level-triggered兩種接口,并且可以高性能的同時監(jiān)視大量的fd,這是對epoll相對魚poll的核心優(yōu)勢。
epoll的核心概念是epoll instance,這是一種內(nèi)核數(shù)據(jù)結(jié)構(gòu),從用戶空間角度看,可以視為一個包含兩種列表的容器:
提供以下3個系統(tǒng)調(diào)用來創(chuàng)建和管理epoll instance:
兩種觸發(fā)模式:level_triggered (LT)和 edge_triggered(ET)
假設(shè)發(fā)生如下場景:
如果使用ET觸發(fā),那么步驟5就會阻塞掛起,這是因為對于ET模式而言,只有當(dāng)緩沖區(qū)數(shù)據(jù)發(fā)生變化時才會觸發(fā)事件(對于讀,“變化”指新數(shù)據(jù)到達(dá))。而對于LT而言,只要緩沖區(qū)中存在數(shù)據(jù),就會一直觸發(fā)。
使用ET時應(yīng)使用非阻塞的fd (即無法讀寫時返回EAGIN,而非阻塞),以避免task阻塞導(dǎo)教其他fd無法監(jiān)控。
合理使用ET模式步驟:
1)修改fd為非阻塞(non-blocking)
2)在read或write操作返回EAGIN后再執(zhí)行wait等待事件。
為何ET需要非阻塞呢?因為ET模式下要循環(huán)多次read,并通過阻塞(即是否返回EAGIN)來確定數(shù)據(jù)是否全部讀完。之一次執(zhí)行read是不可能阻塞的。
若使用LT模式(默認(rèn)情況下,使用ET模式),則可以將epoll看作是一個快速的poll,可以在任何地方使用epoll(LT)替換poll,因為他們的語義完全相同。
即使采用ET模式,在多線程的情況依然會導(dǎo)致產(chǎn)生多個事件(對于同一被監(jiān)控的fd),這將導(dǎo)致多個線程操作同一fd,可以使用EPOLLNESHOT標(biāo)志避免,即在一次wait返回后禁止fd再產(chǎn)生事件,并在處理完成后使用epoll_ctl的MOD操作重新開啟。
在多進(jìn)程或多線程中,epoll_fd是共享的,這將導(dǎo)致所有線程都會知道事情的發(fā)生,但是epoll僅會喚醒一個線程,以規(guī)避“群驚”現(xiàn)象。
If the system is in autosleep mode via /sys/power/autosleep and an event happens which wakes the device from sleep, the device driver will keep the device awake only until that event is queued. To keep the device awake until the event has been processed, it is necessary to use the epoll_ctl(2) EPOLLWAKEUP flag.
When the EPOLLWAKEUP flag is set in the events field for a struct epoll_event, the system will be kept awake from the moment the event is queued, through the epoll_wait(2) call which returns the event until the subsequent epoll_wait(2) call. If the event should keep the system awake beyond that time, then a separate wake_lock should be taken before the second epoll_wait(2) call.
以下接口可用于限制 epoll 消耗的內(nèi)核內(nèi)存用量:
雖然 epoll 在用作級別觸發(fā)接口時具有與 poll(2) 相同的語義,但邊緣觸發(fā)的用法需要更多說明以避免應(yīng)用程序事件循環(huán)中的阻塞。
在下面例子中,listener 是一個非阻塞套接字,在它上面調(diào)用了 listen(2)。 函數(shù) do_use_fd() 使用新的就緒文件描述符,直到 read(2) 或 write(2) 返回 EAGAIN。 事件驅(qū)動的狀態(tài)機(jī)應(yīng)用程序應(yīng)該在收到 EAGAIN 后記錄其當(dāng)前狀態(tài),以便在下一次調(diào)用 do_use_fd() 時,它將繼續(xù)從之前停止的位置read (2) 或write (2)。
當(dāng)使用ET模式時,出于性能原因,可以通過EPOLL_CTL_ADD調(diào)用 epoll_ctl(2)指定 (EPOLLIN|EPOLLOUT)添加一次文件描述符。 避免使用 EPOLL_CTL_MOD 調(diào)用 epoll_ctl(2)在 EPOLLIN 和 EPOLLOUT 之間連續(xù)切換。
The epoll API is Linux-specific. Some other systems provide similar mechanis, for example, FreeBSD has kqueue, and Solaris has /dev/poll.
通過 epoll 文件描述符監(jiān)視的文件描述符集可以通過進(jìn)程的 /proc//fdinfo 目錄中的 epoll 文件描述符條目查看。 有關(guān)更多詳細(xì)信息,請參閱 proc(5)。
關(guān)于linux epoll內(nèi)核實現(xiàn)的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
成都創(chuàng)新互聯(lián)科技公司主營:網(wǎng)站設(shè)計、網(wǎng)站建設(shè)、小程序制作、成都軟件開發(fā)、網(wǎng)頁設(shè)計、微信開發(fā)、成都小程序開發(fā)、網(wǎng)站制作、網(wǎng)站開發(fā)等業(yè)務(wù),是專業(yè)的成都做小程序公司、成都網(wǎng)站建設(shè)公司、成都做網(wǎng)站的公司。創(chuàng)新互聯(lián)公司集小程序制作創(chuàng)意,網(wǎng)站制作策劃,畫冊、網(wǎng)頁、VI設(shè)計,網(wǎng)站、軟件、微信、小程序開發(fā)于一體。
本文題目:Linuxepoll內(nèi)核實現(xiàn)詳解(linuxepoll內(nèi)核實現(xiàn))
文章URL:http://m.5511xx.com/article/dpdjigg.html


咨詢
建站咨詢
