epoll 可以說(shuō)是編寫(xiě)高性能服務(wù)端程序必不可少的技術(shù),在介紹 epoll 之前,我們先來(lái)了解一下 多路復(fù)用I/O 吧。
多路復(fù)用I/O多路復(fù)用I/O:是指內(nèi)核負(fù)責(zé)監(jiān)聽(tīng)多個(gè) I/O 流,當(dāng)任何一個(gè) I/O 流處于就緒狀態(tài)(可讀或可寫(xiě))時(shí)都會(huì)通知進(jìn)程,以便可以處理該 I/O 流上的數(shù)據(jù)。如 圖1 所示:
如 圖1 所示,內(nèi)核負(fù)責(zé)監(jiān)聽(tīng)多個(gè) I/O 流,當(dāng)某些 I/O 流變?yōu)榫途w狀態(tài),內(nèi)核會(huì)把這些 I/O 流添加到就緒隊(duì)列中,然后通知進(jìn)程處理就緒隊(duì)列中的 I/O 流。
與傳統(tǒng)的阻塞型 I/O 相比,多路復(fù)用 I/O 的優(yōu)點(diǎn)是可以同時(shí)監(jiān)聽(tīng)多個(gè) I/O 流,并且會(huì)把就緒的 I/O 流告知進(jìn)程。
epoll原理介紹完多路復(fù)用 I/O,接下來(lái)開(kāi)始介紹我們的主角:epoll。
在 Linux 系統(tǒng)中,有多種多路復(fù)用 I/O 的實(shí)現(xiàn),比如 select 和 poll 等。而 epoll 也是多路復(fù)用 I/O 一種實(shí)現(xiàn),與 select 和 poll 相比,epoll 在性能上有較大的提升。
紅黑樹(shù)
epoll 內(nèi)部使用紅黑樹(shù)來(lái)保存所有監(jiān)聽(tīng)的 socket,紅黑樹(shù)是一種平衡二叉樹(shù),添加和查找元素的時(shí)間復(fù)雜度為 O(log n),其結(jié)構(gòu)如 圖2 所示:
epoll 通過(guò) socket 句柄來(lái)作為 key,把 socket 保存在紅黑樹(shù)中。如 圖2 所示,每個(gè)節(jié)點(diǎn)中的數(shù)字代表著 socket 句柄。
把監(jiān)聽(tīng)的 socket 保存在紅黑樹(shù)中的目的是,為了在修改監(jiān)聽(tīng) socket 的讀寫(xiě)事件時(shí),能夠通過(guò) socket 句柄快速找到對(duì)應(yīng)的 socket 對(duì)象。
就緒隊(duì)列
另外,epoll 還維護(hù)著一個(gè)就緒隊(duì)列,當(dāng) epoll 監(jiān)聽(tīng)的 socket 狀態(tài)發(fā)生改變(變?yōu)榭勺x或可寫(xiě))時(shí),就會(huì)把就緒的 socket 添加到就緒隊(duì)列中。如 圖3 所示:
當(dāng) socket 從網(wǎng)絡(luò)中獲取到數(shù)據(jù)后,會(huì)發(fā)生通知給 epoll,epoll 會(huì)將當(dāng)前 socket 添加到就緒隊(duì)列中,并且喚醒等待中的進(jìn)程(也就是調(diào)用 epoll_wait 的進(jìn)程)。
當(dāng) socket 狀態(tài)發(fā)生變化時(shí),會(huì)調(diào)用 ep_poll_callback 函數(shù)來(lái)通知 epoll,我們來(lái)看看這個(gè)函數(shù)的處理過(guò)程:
static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key){ 。。. struct epitem *epi = ep_item_from_wait(wait); struct eventpoll *ep = epi-》ep; 。。. // 1) 把 socket 添加到就緒隊(duì)列中 list_add_tail(&epi-》rdllink, &ep-》rdllist);
is_linked: // 2) 喚醒調(diào)用 epoll_wait() 而被阻塞的進(jìn)程 if (waitqueue_active(&ep-》wq)) wake_up_locked(&ep-》wq); 。。. return 1;}
ep_poll_callback 函數(shù)的意圖很清晰,主要完成兩個(gè)工作:
把就緒的 socket 添加到就緒隊(duì)列中。
喚醒調(diào)用 epoll_wait 函數(shù)而被阻塞的進(jìn)程。
當(dāng)進(jìn)程被喚醒后,就會(huì)從就緒隊(duì)列中,把就緒的 socket 復(fù)制到用戶提供的數(shù)組中。如 圖4 所示:
如 圖4 所示,在調(diào)用 epoll_wait 時(shí)需要提供一個(gè) events 數(shù)組來(lái)存儲(chǔ)就緒的 socket。當(dāng) epoll_wait 返回后,用戶就可以從events 數(shù)組中獲取到就緒的 socket,并可對(duì)其進(jìn)行讀寫(xiě)操作。
總結(jié)本文主要通過(guò)圖解的方式大概介紹了 epoll 的原理,但很多實(shí)現(xiàn)的細(xì)節(jié)只能通過(guò)閱讀源碼來(lái)了解。
編輯:jq
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
7297瀏覽量
93499 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4401瀏覽量
66462 -
epoll
+關(guān)注
關(guān)注
0文章
28瀏覽量
3257
原文標(biāo)題:圖解:epoll怎么實(shí)現(xiàn)的
文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
HarmonyOSAI編程智能代碼解讀
AI SoC #BK7258 AI能力和技術(shù)參數(shù)深度解讀

直播 | GB/T 45086與ISO11451標(biāo)準(zhǔn)深度解讀研討會(huì)筆記請(qǐng)查收!

革命性神經(jīng)形態(tài)微控制器 ?**Pulsar**? 的深度技術(shù)解讀

瑞薩365 深度解讀

蘋(píng)果A20芯片的深度解讀
ARM Mali GPU 深度解讀
Arm 公司面向 PC 市場(chǎng)的 ?Arm Niva? 深度解讀
Arm 公司面向移動(dòng)端市場(chǎng)的 ?Arm Lumex? 深度解讀
Arm 公司面向汽車市場(chǎng)的 ?Arm Zena? 深度解讀
兆易創(chuàng)新人形機(jī)器人方案 深度解讀
谷歌第七代TPU Ironwood深度解讀:AI推理時(shí)代的硬件革命

評(píng)論