chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

深度剖析Linux的epoll機(jī)制

Linux愛(ài)好者 ? 來(lái)源:奇伢云存儲(chǔ) ? 作者:奇伢 ? 2021-07-29 10:52 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

Linux 系統(tǒng)之中有一個(gè)核心武器:epoll 池,在高并發(fā)的,高吞吐的 IO 系統(tǒng)中常常見(jiàn)到 epoll 的身影。

IO 多路復(fù)用

在 Go 里最核心的是 Goroutine ,也就是所謂的協(xié)程,協(xié)程最妙的一個(gè)實(shí)現(xiàn)就是異步的代碼長(zhǎng)的跟同步代碼一樣。比如在 Go 中,網(wǎng)絡(luò) IO 的 read,write 看似都是同步代碼,其實(shí)底下都是異步調(diào)用,一般流程是:

write ( /* IO 參數(shù) */ )

請(qǐng)求入隊(duì)

等待完成

后臺(tái) loop 程序

發(fā)送網(wǎng)絡(luò)請(qǐng)求

喚醒業(yè)務(wù)方

Go 配合協(xié)程在網(wǎng)絡(luò) IO 上實(shí)現(xiàn)了異步流程的代碼同步化。核心就是用 epoll 池來(lái)管理網(wǎng)絡(luò) fd 。

實(shí)現(xiàn)形式上,后臺(tái)的程序只需要 1 個(gè)就可以負(fù)責(zé)管理多個(gè) fd 句柄,負(fù)責(zé)應(yīng)對(duì)所有的業(yè)務(wù)方的 IO 請(qǐng)求。這種一對(duì)多的 IO 模式我們就叫做 IO 多路復(fù)用。

多路是指?多個(gè)業(yè)務(wù)方(句柄)并發(fā)下來(lái)的 IO 。

復(fù)用是指?復(fù)用這一個(gè)后臺(tái)處理程序。

站在 IO 系統(tǒng)設(shè)計(jì)人員的角度,業(yè)務(wù)方咱們沒(méi)辦法提要求,因?yàn)闃I(yè)務(wù)是上帝,只有你服從的份,他們要?jiǎng)?chuàng)建多個(gè) fd,那么你就需要負(fù)責(zé)這些 fd 的處理,并且最好還要并發(fā)起來(lái)。

業(yè)務(wù)方?jīng)]法提要求,那么只能要求后臺(tái) loop 程序了!

要求什么呢?快!快!快!這就是最核心的要求,處理一定要快,要給每一個(gè) fd 通道最快的感受,要讓每一個(gè) fd 覺(jué)得,你只在給他一個(gè)人跑腿。

那有人又問(wèn)了,那我一個(gè) IO 請(qǐng)求(比如 write )對(duì)應(yīng)一個(gè)線(xiàn)程來(lái)處理,這樣所有的 IO 不都并發(fā)了嗎?是可以,但是有瓶頸,線(xiàn)程數(shù)一旦多了,性能是反倒會(huì)差的。

這里不再對(duì)比多線(xiàn)程和 IO 多路復(fù)用實(shí)現(xiàn)高并發(fā)之間的區(qū)別,詳細(xì)的可以去了解下 nginx 和 redis 高并發(fā)的秘密。

1 最樸實(shí)的實(shí)現(xiàn)方式?

我不用任何其他系統(tǒng)調(diào)用,能否實(shí)現(xiàn) IO 多路復(fù)用?

可以的。那么寫(xiě)個(gè) for 循環(huán),每次都嘗試 IO 一下,讀/寫(xiě)到了就處理,讀/寫(xiě)不到就 sleep 下。這樣我們不就實(shí)現(xiàn)了 1 對(duì)多的 IO 多路復(fù)用嘛。

while True:

for each 句柄數(shù)組 {

read/write(fd, /* 參數(shù) */)

}

sleep(1s)

慢著,有個(gè)問(wèn)題,上面的程序可能會(huì)被卡死在第三行,使得整個(gè)系統(tǒng)不得運(yùn)行,為什么?

默認(rèn)情況下,我們 create 出的句柄是阻塞類(lèi)型的。我們讀數(shù)據(jù)的時(shí)候,如果數(shù)據(jù)還沒(méi)準(zhǔn)備好,是會(huì)需要等待的,當(dāng)我們寫(xiě)數(shù)據(jù)的時(shí)候,如果還沒(méi)準(zhǔn)備好,默認(rèn)也會(huì)卡住等待。所以,在上面?zhèn)未a第三行是可能被直接卡死,而導(dǎo)致整個(gè)線(xiàn)程都得到不到運(yùn)行。

舉個(gè)例子,現(xiàn)在有 11,12,13 這 3 個(gè)句柄,現(xiàn)在 11 讀寫(xiě)都沒(méi)有準(zhǔn)備好,只要 read/write(11, /*參數(shù)*/) 就會(huì)被卡住,但 12,13 這兩個(gè)句柄都準(zhǔn)備好了,那遍歷句柄數(shù)組 11,12,13 的時(shí)候就會(huì)卡死在前面,后面 12,13 則得不到運(yùn)行。這不符合我們的預(yù)期,因?yàn)槲覀?IO 多路復(fù)用的 loop 線(xiàn)程是公共服務(wù),不能因?yàn)橐粋€(gè) fd 就直接癱瘓。

那這個(gè)問(wèn)題怎么解決?

只需要把 fd 都設(shè)置成非阻塞模式。這樣 read/write 的時(shí)候,如果數(shù)據(jù)沒(méi)準(zhǔn)備好,返回 EAGIN 的錯(cuò)誤即可,不會(huì)卡住線(xiàn)程,從而整個(gè)系統(tǒng)就運(yùn)轉(zhuǎn)起來(lái)了。比如上面句柄 11 還未就緒,那么 read/write(11, /*參數(shù)*/) 不會(huì)阻塞,只會(huì)報(bào)個(gè) EAGIN 的錯(cuò)誤,這種錯(cuò)誤需要特殊處理,然后 loop 線(xiàn)程可以繼續(xù)執(zhí)行 12,13 的讀寫(xiě)。

以上就是最樸實(shí)的 IO 多路復(fù)用的實(shí)現(xiàn)了。但好像在生產(chǎn)環(huán)境沒(méi)見(jiàn)過(guò)這種 IO 多路復(fù)用的實(shí)現(xiàn)?為什么?

因?yàn)檫€不夠高級(jí)。for 循環(huán)每次要定期 sleep 1s,這個(gè)會(huì)導(dǎo)致吞吐能力極差,因?yàn)楹芸赡茉趧偤靡?sleep 的時(shí)候,所有的 fd 都準(zhǔn)備好 IO 數(shù)據(jù),而這個(gè)時(shí)候卻要硬生生的等待 1s,可想而知。。。

那有同學(xué)又要質(zhì)疑了,那 for 循環(huán)里面就不 sleep 嘛,這樣不就能及時(shí)處理了嗎?

及時(shí)是及時(shí)了,但是 CPU 估計(jì)要跑飛了。不加 sleep ,那在沒(méi)有 fd 需要處理的時(shí)候,估計(jì) CPU 都要跑到 100% 了。這個(gè)也是無(wú)法接受的。

糾結(jié)了,那 sleep 吞吐不行,不 sleep 浪費(fèi) cpu,怎么辦?

這種情況用戶(hù)態(tài)很難有所作為,只能求助內(nèi)核來(lái)提供機(jī)制協(xié)助來(lái)。因?yàn)閮?nèi)核才能及時(shí)的管理這些事件的通知和調(diào)度。

我們?cè)偈崂硐?IO 多路復(fù)用的需求和原理。IO 多路復(fù)用就是 1 個(gè)線(xiàn)程處理 多個(gè) fd 的模式。我們的要求是:這個(gè) “1” 就要盡可能的快,避免一切無(wú)效工作,要把所有的時(shí)間都用在處理句柄的 IO 上,不能有任何空轉(zhuǎn),sleep 的時(shí)間浪費(fèi)。

有沒(méi)有一種工具,我們把一籮筐的 fd 放到里面,只要有一個(gè) fd 能夠讀寫(xiě)數(shù)據(jù),后臺(tái) loop 線(xiàn)程就要立馬喚醒,全部馬力跑起來(lái)。其他時(shí)間要把 cpu 讓出去。

能做到嗎?能,但這種需求只能內(nèi)核提供機(jī)制滿(mǎn)足你。

2 這事 Linux 內(nèi)核必須要給個(gè)說(shuō)法?

是的,想要不用 sleep 這種辣眼睛的實(shí)現(xiàn),Linux 內(nèi)核必須出手了,畢竟 IO 的處理都是內(nèi)核之中,數(shù)據(jù)好沒(méi)好內(nèi)核最清楚。

內(nèi)核一口氣提供了 3 種工具 select,poll,epoll 。

為什么有 3 種?

歷史不斷改進(jìn),矬 -》 較矬 -》 臥槽、高效 的演變而已。

Linux 還有其他方式可以實(shí)現(xiàn) IO 多路復(fù)用嗎?

好像沒(méi)有了!

這 3 種到底是做啥的?

這 3 種都能夠管理 fd 的可讀可寫(xiě)事件,在所有 fd 不可讀不可寫(xiě)無(wú)所事事的時(shí)候,可以阻塞線(xiàn)程,切走 cpu 。fd 有情況的時(shí)候,都要線(xiàn)程能夠要能被喚醒。

而這三種方式以 epoll 池的效率最高。為什么效率最高?

其實(shí)很簡(jiǎn)單,這里不詳說(shuō),其實(shí)無(wú)非就是 epoll 做的無(wú)用功最少,select 和 poll 或多或少都要多余的拷貝,盲猜(遍歷才知道)fd ,所以效率自然就低了。

舉個(gè)例子,以 select 和 epoll 來(lái)對(duì)比舉例,池子里管理了 1024 個(gè)句柄,loop 線(xiàn)程被喚醒的時(shí)候,select 都是蒙的,都不知道這 1024 個(gè) fd 里誰(shuí) IO 準(zhǔn)備好了。這種情況怎么辦?只能遍歷這 1024 個(gè) fd ,一個(gè)個(gè)測(cè)試。假如只有一個(gè)句柄準(zhǔn)備好了,那相當(dāng)于做了 1 千多倍的無(wú)效功。

epoll 則不同,從 epoll_wait 醒來(lái)的時(shí)候就能精確的拿到就緒的 fd 數(shù)組,不需要任何測(cè)試,拿到的就是要處理的。

epoll 池原理

下面我們看一下 epoll 池的使用和原理。

1 epoll 涉及的系統(tǒng)調(diào)用

epoll 的使用非常簡(jiǎn)單,只有下面 3 個(gè)系統(tǒng)調(diào)用。

epoll_create

epollctl

epollwait

就這?是的,就這么簡(jiǎn)單。

epollcreate 負(fù)責(zé)創(chuàng)建一個(gè)池子,一個(gè)監(jiān)控和管理句柄 fd 的池子;

epollctl 負(fù)責(zé)管理這個(gè)池子里的 fd 增、刪、改;

epollwait 就是負(fù)責(zé)打盹的,讓出 CPU 調(diào)度,但是只要有“事”,立馬會(huì)從這里喚醒;

2 epoll 高效的原理

Linux 下,epoll 一直被吹爆,作為高并發(fā) IO 實(shí)現(xiàn)的秘密武器。其中原理其實(shí)非常樸實(shí):epoll 的實(shí)現(xiàn)幾乎沒(méi)有做任何無(wú)效功。 我們從使用的角度切入來(lái)一步步分析下。

首先,epoll 的第一步是創(chuàng)建一個(gè)池子。這個(gè)使用 epoll_create 來(lái)做:

原型:

int epoll_create(int size);

示例:

epollfd = epoll_create(1024);

if (epollfd == -1) {

perror(“epoll_create”);

exit(EXIT_FAILURE);

}

這個(gè)池子對(duì)我們來(lái)說(shuō)是黑盒,這個(gè)黑盒是用來(lái)裝 fd 的,我們暫不糾結(jié)其中細(xì)節(jié)。我們拿到了一個(gè) epollfd ,這個(gè) epollfd 就能唯一代表這個(gè) epoll 池。注意,這里又有一個(gè)細(xì)節(jié):用戶(hù)可以創(chuàng)建多個(gè) epoll 池。

然后,我們就要往這個(gè) epoll 池里放 fd 了,這就要用到 epoll_ctl 了

原型:

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

示例:

if (epoll_ctl(epollfd, EPOLL_CTL_ADD, 11, &ev) == -1) {

perror(“epoll_ctl: listen_sock”);

exit(EXIT_FAILURE);

}

上面,我們就把句柄 11 放到這個(gè)池子里了,op(EPOLL_CTL_ADD)表明操作是增加、修改、刪除,event 結(jié)構(gòu)體可以指定監(jiān)聽(tīng)事件類(lèi)型,可讀、可寫(xiě)。

第一個(gè)跟高效相關(guān)的問(wèn)題來(lái)了,添加 fd 進(jìn)池子也就算了,如果是修改、刪除呢?怎么做到快速?

這里就涉及到你怎么管理 fd 的數(shù)據(jù)結(jié)構(gòu)了。

最常見(jiàn)的思路:用 list ,可以嗎?功能上可以,但是性能上拉垮。list 的結(jié)構(gòu)來(lái)管理元素,時(shí)間復(fù)雜度都太高 O(n),每次要一次次遍歷鏈表才能找到位置。池子越大,性能會(huì)越慢。

那有簡(jiǎn)單高效的數(shù)據(jù)結(jié)構(gòu)嗎?

有,紅黑樹(shù)。Linux 內(nèi)核對(duì)于 epoll 池的內(nèi)部實(shí)現(xiàn)就是用紅黑樹(shù)的結(jié)構(gòu)體來(lái)管理這些注冊(cè)進(jìn)程來(lái)的句柄 fd。紅黑樹(shù)是一種平衡二叉樹(shù),時(shí)間復(fù)雜度為 O(log n),就算這個(gè)池子就算不斷的增刪改,也能保持非常穩(wěn)定的查找性能。

現(xiàn)在思考第二個(gè)高效的秘密:怎么才能保證數(shù)據(jù)準(zhǔn)備好之后,立馬感知呢?

epoll_ctl 這里會(huì)涉及到一點(diǎn)。秘密就是:回調(diào)的設(shè)置。在 epoll_ctl 的內(nèi)部實(shí)現(xiàn)中,除了把句柄結(jié)構(gòu)用紅黑樹(shù)管理,另一個(gè)核心步驟就是設(shè)置 poll 回調(diào)。

思考來(lái)了:poll 回調(diào)是什么?怎么設(shè)置?

先說(shuō)說(shuō) file_operations-》poll 是什么?

在 文件描述符 fd 究竟是什么 說(shuō)過(guò),Linux 設(shè)計(jì)成一切皆是文件的架構(gòu),這個(gè)不是說(shuō)說(shuō)而已,而是隨處可見(jiàn)。實(shí)現(xiàn)一個(gè)文件系統(tǒng)的時(shí)候,就要實(shí)現(xiàn)這個(gè)文件調(diào)用,這個(gè)結(jié)構(gòu)體用 struct file_operations 來(lái)表示。這個(gè)結(jié)構(gòu)體有非常多的函數(shù),精簡(jiǎn)了一些,如下:

struct file_operations {

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

__poll_t (*poll) (struct file *, struct poll_table_struct *);

int (*open) (struct inode *, struct file *);

int (*fsync) (struct file *, loff_t, loff_t, int datasync);

// 。。。。

};

你看到了 read,write,open,fsync,poll 等等,這些都是對(duì)文件的定制處理操作,對(duì)于文件的操作其實(shí)都是在這個(gè)框架內(nèi)實(shí)現(xiàn)邏輯而已,比如 ext2 如果有對(duì) read/write 做定制化,那么就會(huì)是 ext2_read,ext2_write,ext4 就會(huì)是 ext4_read,ext4_write。在 open 具體“文件”的時(shí)候會(huì)賦值對(duì)應(yīng)文件系統(tǒng)的 file_operations 給到 file 結(jié)構(gòu)體。

那我們很容易知道 read 是文件系統(tǒng)定制 fd 讀的行為調(diào)用,write 是文件系統(tǒng)定制 fd 寫(xiě)的行為調(diào)用,file_operations-》poll 呢?

這個(gè)是定制監(jiān)聽(tīng)事件的機(jī)制實(shí)現(xiàn)。通過(guò) poll 機(jī)制讓上層能直接告訴底層,我這個(gè) fd 一旦讀寫(xiě)就緒了,請(qǐng)底層硬件(比如網(wǎng)卡)回調(diào)的時(shí)候自動(dòng)把這個(gè) fd 相關(guān)的結(jié)構(gòu)體放到指定隊(duì)列中,并且喚醒操作系統(tǒng)。

舉個(gè)例子:網(wǎng)卡收發(fā)包其實(shí)走的異步流程,操作系統(tǒng)把數(shù)據(jù)丟到一個(gè)指定地點(diǎn),網(wǎng)卡不斷的從這個(gè)指定地點(diǎn)掏數(shù)據(jù)處理。請(qǐng)求響應(yīng)通過(guò)中斷回調(diào)來(lái)處理,中斷一般拆分成兩部分:硬中斷和軟中斷。poll 函數(shù)就是把這個(gè)軟中斷回來(lái)的路上再加點(diǎn)料,只要讀寫(xiě)事件觸發(fā)的時(shí)候,就會(huì)立馬通知到上層,采用這種事件通知的形式就能把浪費(fèi)的時(shí)間窗就完全消失了。

劃重點(diǎn):這個(gè) poll 事件回調(diào)機(jī)制則是 epoll 池高效最核心原理。

劃重點(diǎn):epoll 池管理的句柄只能是支持了 file_operations-》poll 的文件 fd。換句話(huà)說(shuō),如果一個(gè)“文件”所在的文件系統(tǒng)沒(méi)有實(shí)現(xiàn) poll 接口,那么就用不了 epoll 機(jī)制。

第二個(gè)問(wèn)題:poll 怎么設(shè)置?

在 epoll_ctl 下來(lái)的實(shí)現(xiàn)中,有一步是調(diào)用 vfs_poll 這個(gè)里面就會(huì)有個(gè)判斷,如果 fd 所在的文件系統(tǒng)的 file_operations 實(shí)現(xiàn)了 poll ,那么就會(huì)直接調(diào)用,如果沒(méi)有,那么就會(huì)報(bào)告響應(yīng)的錯(cuò)誤碼。

static inline __poll_t vfs_poll(struct file *file, struct poll_table_struct *pt)

{

if (unlikely(!file-》f_op-》poll))

return DEFAULT_POLLMASK;

return file-》f_op-》poll(file, pt);

}

你肯定好奇 poll 調(diào)用里面究竟是實(shí)現(xiàn)了什么?

總結(jié)概括來(lái)說(shuō):掛了個(gè)鉤子,設(shè)置了喚醒的回調(diào)路徑。epoll 跟底層對(duì)接的回調(diào)函數(shù)是:ep_poll_callback,這個(gè)函數(shù)其實(shí)很簡(jiǎn)單,做兩件事情:

把事件就緒的 fd 對(duì)應(yīng)的結(jié)構(gòu)體放到一個(gè)特定的隊(duì)列(就緒隊(duì)列,ready list);

喚醒 epoll ,活來(lái)啦!

當(dāng) fd 滿(mǎn)足可讀可寫(xiě)的時(shí)候就會(huì)經(jīng)過(guò)層層回調(diào),最終調(diào)用到這個(gè)回調(diào)函數(shù),把對(duì)應(yīng) fd 的結(jié)構(gòu)體放入就緒隊(duì)列中,從而把 epoll 從 epoll_wait 出喚醒。

這個(gè)對(duì)應(yīng)結(jié)構(gòu)體是什么?

結(jié)構(gòu)體叫做 epitem ,每個(gè)注冊(cè)到 epoll 池的 fd 都會(huì)對(duì)應(yīng)一個(gè)。

就緒隊(duì)列需要用很高級(jí)的數(shù)據(jù)結(jié)構(gòu)嗎?

就緒隊(duì)列就簡(jiǎn)單了,因?yàn)闆](méi)有查找的需求了呀,只要是在就緒隊(duì)列中的 epitem ,都是事件就緒的,必須處理的。所以就緒隊(duì)列就是一個(gè)最簡(jiǎn)單的雙指針鏈表。

小結(jié)下:epoll 之所以做到了高效,最關(guān)鍵的兩點(diǎn):

內(nèi)部管理 fd 使用了高效的紅黑樹(shù)結(jié)構(gòu)管理,做到了增刪改之后性能的優(yōu)化和平衡;

epoll 池添加 fd 的時(shí)候,調(diào)用 file_operations-》poll ,把這個(gè) fd 就緒之后的回調(diào)路徑安排好。通過(guò)事件通知的形式,做到最高效的運(yùn)行;

epoll 池核心的兩個(gè)數(shù)據(jù)結(jié)構(gòu):紅黑樹(shù)和就緒列表。紅黑樹(shù)是為了應(yīng)對(duì)用戶(hù)的增刪改需求,就緒列表是 fd 事件就緒之后放置的特殊地點(diǎn),epoll 池只需要遍歷這個(gè)就緒鏈表,就能給用戶(hù)返回所有已經(jīng)就緒的 fd 數(shù)組;

3 哪些 fd 可以用 epoll 來(lái)管理?

再來(lái)思考另外一個(gè)問(wèn)題:由于并不是所有的 fd 對(duì)應(yīng)的文件系統(tǒng)都實(shí)現(xiàn)了 poll 接口,所以自然并不是所有的 fd 都可以放進(jìn) epoll 池,那么有哪些文件系統(tǒng)的 file_operations 實(shí)現(xiàn)了 poll 接口?

首先說(shuō),類(lèi)似 ext2,ext4,xfs 這種常規(guī)的文件系統(tǒng)是沒(méi)有實(shí)現(xiàn)的,換句話(huà)說(shuō),這些你最常見(jiàn)的、真的是文件的文件系統(tǒng)反倒是用不了 epoll 機(jī)制的。

那誰(shuí)支持呢?

最常見(jiàn)的就是網(wǎng)絡(luò)套接字:socket 。網(wǎng)絡(luò)也是 epoll 池最常見(jiàn)的應(yīng)用地點(diǎn)。Linux 下萬(wàn)物皆文件,socket 實(shí)現(xiàn)了一套 socket_file_operations 的邏輯( net/socket.c ):

static const struct file_operations socket_file_ops = {

.read_iter = sock_read_iter,

.write_iter = sock_write_iter,

.poll = sock_poll,

// 。。。

};

我們看到 socket 實(shí)現(xiàn)了 poll 調(diào)用,所以 socket fd 是天然可以放到 epoll 池管理的。

還有支持的嗎?

有的,很多。其實(shí) Linux 下還有兩個(gè)很典型的 fd ,常常也會(huì)放到 epoll 池里。

eventfd:eventfd 實(shí)現(xiàn)非常簡(jiǎn)單,故名思義就是專(zhuān)門(mén)用來(lái)做事件通知用的。使用系統(tǒng)調(diào)用 eventfd 創(chuàng)建,這種文件 fd 無(wú)法傳輸數(shù)據(jù),只用來(lái)傳輸事件,常常用于生產(chǎn)消費(fèi)者模式的事件實(shí)現(xiàn);

timerfd:這是一種定時(shí)器 fd,使用 timerfd_create 創(chuàng)建,到時(shí)間點(diǎn)觸發(fā)可讀事件;

小結(jié)一下:

ext2,ext4,xfs 等這種真正的文件系統(tǒng)的 fd ,無(wú)法使用 epoll 管理;

socket fd,eventfd,timerfd 這些實(shí)現(xiàn)了 poll 調(diào)用的可以放到 epoll 池進(jìn)行管理;

其實(shí),在 Linux 的模塊劃分中,eventfd,timerfd,epoll 池都是文件系統(tǒng)的一種模塊實(shí)現(xiàn)。

思考

前面我們已經(jīng)思考了很多知識(shí)點(diǎn),有一些簡(jiǎn)單有趣的知識(shí)點(diǎn),提示給讀者朋友,這里只拋磚引玉。

問(wèn)題:?jiǎn)魏?CPU 能實(shí)現(xiàn)并行嗎?

不行。

問(wèn)題:?jiǎn)尉€(xiàn)程能實(shí)現(xiàn)高并發(fā)嗎?

可以。

問(wèn)題:那并發(fā)和并行的區(qū)別是?

一個(gè)看的是時(shí)間段內(nèi)的執(zhí)行情況,一個(gè)看的是時(shí)間時(shí)刻的執(zhí)行情況。

問(wèn)題:?jiǎn)尉€(xiàn)程如何做到高并發(fā)?

IO 多路復(fù)用唄,今天講的 epoll 池就是了。

問(wèn)題:?jiǎn)尉€(xiàn)程實(shí)現(xiàn)并發(fā)的有開(kāi)源的例子嗎?

redis,nginx 都是非常好的學(xué)習(xí)例子。當(dāng)然還有我們 Golang 的 runtime 實(shí)現(xiàn)也盡顯高并發(fā)的設(shè)計(jì)思想。

總結(jié)

IO 多路復(fù)用的原始實(shí)現(xiàn)很簡(jiǎn)單,就是一個(gè) 1 對(duì)多的服務(wù)模式,一個(gè) loop 對(duì)應(yīng)處理多個(gè) fd ;

IO 多路復(fù)用想要做到真正的高效,必須要內(nèi)核機(jī)制提供。因?yàn)?IO 的處理和完成是在內(nèi)核,如果內(nèi)核不幫忙,用戶(hù)態(tài)的程序根本無(wú)法精確的抓到處理時(shí)機(jī);

fd 記得要設(shè)置成非阻塞的哦,切記;

epoll 池通過(guò)高效的內(nèi)部管理結(jié)構(gòu),并且結(jié)合操作系統(tǒng)提供的 poll 事件注冊(cè)機(jī)制,實(shí)現(xiàn)了高效的 fd 事件管理,為高并發(fā)的 IO 處理提供了前提條件;

epoll 全名 eventpoll,在 Linux 內(nèi)核下以一個(gè)文件系統(tǒng)模塊的形式實(shí)現(xiàn),所以有人常說(shuō) epoll 其實(shí)本身就是文件系統(tǒng)也是對(duì)的;

socketfd,eventfd,timerfd 這三種”文件“fd 實(shí)現(xiàn)了 poll 接口,所以網(wǎng)絡(luò) fd,事件fd,定時(shí)器fd 都可以使用 epoll_ctl 注冊(cè)到池子里。我們最常見(jiàn)的就是網(wǎng)絡(luò)fd的多路復(fù)用;

ext2,ext4,xfs 這種真正意義的文件系統(tǒng)反倒沒(méi)有提供 poll 接口實(shí)現(xiàn),所以不能用 epoll 池來(lái)管理其句柄。那文件就無(wú)法使用 epoll 機(jī)制了嗎?不是的,有一個(gè)庫(kù)叫做 libaio ,通過(guò)這個(gè)庫(kù)我們可以間接的讓文件使用 epoll 通知事件,以后詳說(shuō),此處不表;

后記

epoll 池使用很簡(jiǎn)潔,但實(shí)現(xiàn)不簡(jiǎn)單。還是那句話(huà),Linux 內(nèi)核幫你包圓了。今天并沒(méi)有羅列太多源碼實(shí)現(xiàn),以很小的思考點(diǎn)為題展開(kāi),簡(jiǎn)單講了一些 epoll 的思考。

編輯:jq

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    88

    文章

    11576

    瀏覽量

    216689

原文標(biāo)題:深入理解 Linux 的 epoll 機(jī)制

文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    教程來(lái)啦!LuatOS中的消息通信機(jī)制詳解及其應(yīng)用場(chǎng)景

    在資源受限的嵌入式環(huán)境中,LuatOS采用消息機(jī)制實(shí)現(xiàn)模塊間解耦與高效通信。通過(guò)預(yù)定義消息名稱(chēng)(如“new_msg”),開(kāi)發(fā)者可輕松構(gòu)建響應(yīng)式程序結(jié)構(gòu)。接下來(lái)我們將深入剖析其實(shí)現(xiàn)原理與典型使用方法
    的頭像 發(fā)表于 09-26 18:59 ?96次閱讀
    教程來(lái)啦!LuatOS中的消息通信<b class='flag-5'>機(jī)制</b>詳解及其應(yīng)用場(chǎng)景

    深度剖析Redis的兩大持久化機(jī)制

    凌晨3點(diǎn),我被一通緊急電話(huà)驚醒。線(xiàn)上Redis集群崩潰,6GB的緩存數(shù)據(jù)全部丟失,導(dǎo)致MySQL瞬間承壓暴增,整個(gè)交易系統(tǒng)陷入癱瘓。事后復(fù)盤(pán)發(fā)現(xiàn),問(wèn)題的根源竟是一個(gè)被忽視的持久化配置細(xì)節(jié)。
    的頭像 發(fā)表于 09-17 16:22 ?230次閱讀

    邊聊安全 | 安全芯片的守護(hù)神:BIST機(jī)制深度解析

    BIST機(jī)制深度解析寫(xiě)在前面:在安全芯片的設(shè)計(jì)與驗(yàn)證過(guò)程中,工程師常會(huì)遇到一個(gè)關(guān)鍵概念——BIST(Built-InSelf-Test,內(nèi)置自檢測(cè))。初次接觸這一術(shù)語(yǔ)時(shí),許多人容易將其簡(jiǎn)單理解為
    的頭像 發(fā)表于 09-05 16:17 ?29次閱讀
    邊聊安全 | 安全芯片的守護(hù)神:BIST<b class='flag-5'>機(jī)制</b>的<b class='flag-5'>深度</b>解析

    GraniStudio : MC 協(xié)議深度剖析

    作為工業(yè)級(jí)零代碼開(kāi)發(fā)平臺(tái),其內(nèi)置的 MC 協(xié)議客戶(hù)端模塊通過(guò)高度封裝的可視化功能,將復(fù)雜的協(xié)議細(xì)節(jié)轉(zhuǎn)化為 “拖拽式” 操作。本文將聚焦 MC 協(xié)議客戶(hù)端的 機(jī)制設(shè)置、幀結(jié)構(gòu)、通信規(guī)范及交互流程 ,結(jié)合 GraniStudio 的功能實(shí)現(xiàn),展開(kāi)技術(shù)細(xì)節(jié)的深度解析。 一、MC
    的頭像 發(fā)表于 08-04 09:57 ?701次閱讀
    GraniStudio : MC 協(xié)議<b class='flag-5'>深度</b><b class='flag-5'>剖析</b>

    GraniStudio :MQTT 協(xié)議的深度剖析

    和 QoS 保障等機(jī)制封裝為可視化組件,為工業(yè)用戶(hù)提供了 “零代碼” 構(gòu)建 MQTT 通信鏈路的能力。本文將從協(xié)議原
    的頭像 發(fā)表于 08-04 09:48 ?651次閱讀
    GraniStudio :MQTT 協(xié)議的<b class='flag-5'>深度</b><b class='flag-5'>剖析</b>

    Linux系統(tǒng)目錄結(jié)構(gòu)全面剖析

    Linux文件系統(tǒng)采用層次化的目錄結(jié)構(gòu),這種設(shè)計(jì)遵循了Unix哲學(xué)中的"一切皆文件"原則。理解Linux目錄層次架構(gòu)對(duì)于系統(tǒng)管理員、運(yùn)維工程師和開(kāi)發(fā)人員來(lái)說(shuō)至關(guān)重要,它不僅影響系統(tǒng)的組織方式,還直接關(guān)系到系統(tǒng)的可維護(hù)性、安全性和性能。
    的頭像 發(fā)表于 07-21 17:33 ?455次閱讀

    切割深度動(dòng)態(tài)補(bǔ)償技術(shù)對(duì)晶圓 TTV 厚度均勻性的提升機(jī)制與參數(shù)優(yōu)化

    厚度不均勻 。切割深度動(dòng)態(tài)補(bǔ)償技術(shù)通過(guò)實(shí)時(shí)調(diào)整切割深度,為提升晶圓 TTV 厚度均勻性提供了有效手段,深入研究其提升機(jī)制與參數(shù)優(yōu)化方法具有重要的現(xiàn)實(shí)意義。 二、
    的頭像 發(fā)表于 07-17 09:28 ?271次閱讀
    切割<b class='flag-5'>深度</b>動(dòng)態(tài)補(bǔ)償技術(shù)對(duì)晶圓 TTV 厚度均勻性的提升<b class='flag-5'>機(jī)制</b>與參數(shù)優(yōu)化

    從接口到架構(gòu):工控一體機(jī)定制化的深度技術(shù)剖析

    工業(yè)場(chǎng)景需求的關(guān)鍵路徑。本文將從接口設(shè)計(jì)、硬件架構(gòu)、操作系統(tǒng)、通信協(xié)議及智能決策五個(gè)維度,深度剖析工控一體機(jī)定制化的技術(shù)內(nèi)核。 一、接口定制化:工業(yè)互聯(lián)的“神經(jīng)末梢” 工控一體機(jī)的接口設(shè)計(jì)直接影響其與外部設(shè)備的兼容
    的頭像 發(fā)表于 06-17 16:47 ?307次閱讀

    全面剖析倒裝芯片封裝技術(shù)的內(nèi)在機(jī)制、特性?xún)?yōu)勢(shì)、面臨的挑戰(zhàn)及未來(lái)走向

    半導(dǎo)體技術(shù)的日新月異,正引領(lǐng)著集成電路封裝工藝的不斷革新與進(jìn)步。其中,倒裝芯片(Flip Chip)封裝技術(shù)作為一種前沿的封裝工藝,正逐漸占據(jù)半導(dǎo)體行業(yè)的核心地位。本文旨在全面剖析倒裝芯片封裝技術(shù)的內(nèi)在機(jī)制、特性、優(yōu)勢(shì)、面臨的挑戰(zhàn)及其未來(lái)走向。
    的頭像 發(fā)表于 03-14 10:50 ?1240次閱讀

    2025年常用實(shí)時(shí)Linux系統(tǒng)深度評(píng)測(cè)

    1、PREEMPT-RT - 特性: ?- 實(shí)時(shí)性:通過(guò)內(nèi)核補(bǔ)丁實(shí)現(xiàn)搶占式調(diào)度,響應(yīng)延遲處于毫秒級(jí)別,能夠滿(mǎn)足一般實(shí)時(shí)應(yīng)用的需求。 ?- 兼容性:與標(biāo)準(zhǔn)Linux內(nèi)核高度兼容,支持廣泛的硬件平臺(tái)
    的頭像 發(fā)表于 03-06 10:57 ?939次閱讀

    BNC 連接器接線(xiàn)原理深度剖析

    使用和維護(hù)相關(guān)設(shè)備、保障系統(tǒng)的穩(wěn)定運(yùn)行至關(guān)重要。接下來(lái),本文將從德索工程師的專(zhuān)業(yè)視角出發(fā),為大家詳細(xì)剖析 BNC 連接器從結(jié)構(gòu)到信號(hào)傳輸?shù)脑怼?/div>
    的頭像 發(fā)表于 02-28 08:45 ?790次閱讀
    BNC 連接器接線(xiàn)原理<b class='flag-5'>深度</b><b class='flag-5'>剖析</b>

    深度解讀 30KPA64A 單向 TVS:64V 擊穿機(jī)制與高效防護(hù)策略

    深度解讀 30KPA64A 單向 TVS:64V 擊穿機(jī)制與高效防護(hù)策略
    的頭像 發(fā)表于 02-24 13:52 ?510次閱讀
    <b class='flag-5'>深度</b>解讀 30KPA64A 單向 TVS:64V 擊穿<b class='flag-5'>機(jī)制</b>與高效防護(hù)策略

    隔離型DCDC偏置電源供應(yīng)技術(shù)深度剖析

    型DC/DC偏置電源供應(yīng)的技術(shù)特點(diǎn)、拓?fù)浣Y(jié)構(gòu)、新一代解決方案及選擇策略,為相關(guān)領(lǐng)域的設(shè)計(jì)師提供參考。 *附件:隔離型DCDC偏置電源供應(yīng)技術(shù)深度剖析.pdf 2. 隔離型DC/DC偏置電源供應(yīng)概述 隔離型DC/DC偏置電源供應(yīng)是指能夠跨越隔離屏障提供穩(wěn)定電
    的頭像 發(fā)表于 02-14 11:05 ?1634次閱讀
    隔離型DCDC偏置電源供應(yīng)技術(shù)<b class='flag-5'>深度</b><b class='flag-5'>剖析</b>

    深入探討Linux系統(tǒng)中的動(dòng)態(tài)鏈接庫(kù)機(jī)制

    本文將深入探討Linux系統(tǒng)中的動(dòng)態(tài)鏈接庫(kù)機(jī)制,這其中包括但不限于全局符號(hào)介入、延遲綁定以及地址無(wú)關(guān)代碼等內(nèi)容。 引言 在軟件開(kāi)發(fā)過(guò)程中,動(dòng)態(tài)庫(kù)鏈接問(wèn)題時(shí)常出現(xiàn),這可能導(dǎo)致符號(hào)沖突,從而引起程序運(yùn)行
    的頭像 發(fā)表于 12-18 10:06 ?805次閱讀
    深入探討<b class='flag-5'>Linux</b>系統(tǒng)中的動(dòng)態(tài)鏈接庫(kù)<b class='flag-5'>機(jī)制</b>

    Linux--IO多路復(fù)用(select,poll,epoll)

    ,常用的系統(tǒng)調(diào)用包括select()、poll()和epoll()。這些機(jī)制允許程序監(jiān)視多個(gè)描述符,一旦某個(gè)描述符就緒(通常是讀就緒或?qū)懢途w),程序就會(huì)被通知進(jìn)行相應(yīng)的讀寫(xiě)操作。這個(gè)過(guò)程通常涉及兩個(gè)階段
    的頭像 發(fā)表于 11-06 16:13 ?1365次閱讀