成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

徹底搞懂 Select / Poll / Epoll,就這篇了!

開發(fā) 前端
假設(shè)此時(shí)客戶端發(fā)送了數(shù)據(jù),網(wǎng)卡接收到的數(shù)據(jù)塞到對(duì)應(yīng)的 socket 的接收隊(duì)列中,此時(shí) socket 知道來(lái)數(shù)據(jù)了,那如何喚醒 select 呢?

之前已經(jīng)把網(wǎng)絡(luò) I/O 相關(guān)要點(diǎn)都盤了,還剩 select/poll/epoll 這幾個(gè)區(qū)別沒(méi)說(shuō),這篇就來(lái)搞搞它們,并且是從完全理解原理的角度來(lái)區(qū)分它們。

本來(lái)是要上源碼的,但是感覺(jué)沒(méi)啥必要,身為應(yīng)用開發(fā)我覺(jué)得理解原理就行了,源碼反正看了就忘了,理解才是最重要!所以我就盡量避免代碼且用大白話來(lái)盤一盤這三個(gè)玩意。

話不多說(shuō),發(fā)車。

小思考

首先,我們知道 select/poll/epoll 是用來(lái)實(shí)現(xiàn)多路復(fù)用的,即一個(gè)線程利用它們即可 hold 住多個(gè) socket。

按照這個(gè)思路,線程不可被任何一個(gè)被管理的 Socket 阻塞,且任一個(gè) Socket 來(lái)數(shù)據(jù)之后都得告知 select/poll/epoll 線程。

想想看,這應(yīng)該如何實(shí)現(xiàn)呢?

我們拿 select 的邏輯來(lái)分析下

按照我們的理解,select 管理多個(gè) Socket 的模型如下圖所示:

這里要注意一下內(nèi)核態(tài)和用戶態(tài)的交互,用戶程序訪問(wèn)不了內(nèi)核空間。

所以,我們調(diào)用 select 會(huì)把所有要管理的 socket 的 fd (文件描述符,Linux下皆為文件,簡(jiǎn)單理解就是通過(guò) fd 能找到這個(gè) socket)傳到內(nèi)核中。

此時(shí),要遍歷所有 socket,看看是否有感興趣的事件發(fā)生。如果沒(méi)有一個(gè) socket 有事件發(fā)生,那么 select 的線程就需要讓出 cpu 阻塞等待,這個(gè)等待可以是不設(shè)置超時(shí)時(shí)間的死等,也可以是設(shè)置 timeout 的有超時(shí)時(shí)間的等待。

假設(shè)此時(shí)客戶端發(fā)送了數(shù)據(jù),網(wǎng)卡接收到的數(shù)據(jù)塞到對(duì)應(yīng)的 socket 的接收隊(duì)列中,此時(shí) socket 知道來(lái)數(shù)據(jù)了,那如何喚醒 select 呢?

其實(shí)每個(gè) socket 有個(gè)屬于自己的睡眠隊(duì)列,select 會(huì)安排一個(gè)內(nèi)應(yīng),即在被管理的 socket 的睡眠隊(duì)列里面塞入一個(gè) entry。

當(dāng) socket 接收到網(wǎng)卡的數(shù)據(jù)后,就會(huì)去它的睡眠隊(duì)列里遍歷 entry,調(diào)用 entry 設(shè)置的 callback 方法,這個(gè) callback 方法里就能喚醒 select !

所以 select 在每個(gè)被它管理的 socket 的睡眠隊(duì)列里都塞入一個(gè)與它相關(guān)的 entry,這樣不論哪個(gè) socket 來(lái)數(shù)據(jù)了,它立馬就能被喚醒然后干活!

但是,select 的實(shí)現(xiàn)不太好,因?yàn)閱拘训?select 此時(shí)只知道來(lái)活了,并不知道具體是哪個(gè) socket 來(lái)數(shù)據(jù)了,所以只能傻傻地遍歷所有 socket ,看看到底是哪個(gè) scoket 來(lái)活了,然后把所有來(lái)活的 socket 封裝成事件返回。

這樣用戶程序就能獲得發(fā)生的事件,然后進(jìn)行 I/O 和業(yè)務(wù)處理了。

這就是 select 的實(shí)現(xiàn)邏輯,理解起來(lái)應(yīng)該不難。

這里再提一嘴 select 的限制,因?yàn)楸还芾淼?socket fd 需要從用戶空間拷貝到內(nèi)核空間,為了控制拷貝的大小而做了限制,即每個(gè) select 能拷貝的 fds 集合大小只有1024。

然后要改的話只能修改宏..再重新編譯內(nèi)核。網(wǎng)上很多文章都是這樣說(shuō)的,但是(沒(méi)錯(cuò)有個(gè)但是)。

我看了一篇文章,確實(shí)有這個(gè)宏,值也是 1024,但內(nèi)核根本沒(méi)有限制 fds 集合的大小。然后托人問(wèn)了個(gè)內(nèi)核大佬,大佬說(shuō)內(nèi)核確實(shí)沒(méi)做限制,glibc那層做了。

所以..重新編譯內(nèi)核?那篇文章放文末。

poll

poll 這玩意相比于 select 主要就是優(yōu)化了 fds 的結(jié)構(gòu),不再是 bit 數(shù)組了,而是一個(gè)叫 pollfd 的玩意,反正就是不用管啥 1024 的限制了。

不過(guò)現(xiàn)在也沒(méi)人用 poll,我就不多說(shuō)了。

epoll

這個(gè)就是重點(diǎn)了。

相信看了 select 的實(shí)現(xiàn),我們稍微思考下,就能想出幾個(gè)可以優(yōu)化的點(diǎn)。

比如,為什么每次 select 需要把監(jiān)控的 fds 傳輸?shù)絻?nèi)核里?不能在內(nèi)核里維護(hù)個(gè)?

為什么 socket 只喚醒 select,不能告訴它是哪個(gè) socket 來(lái)數(shù)據(jù)了?

epoll 主要就是基于上面兩點(diǎn)做了優(yōu)化。

首先,搞了個(gè)叫 epoll_ctl 的方法,這方法就是用來(lái)管理維護(hù) epoll 所監(jiān)控的哪些 socket。

如果你的 epoll 要新加一個(gè) socket 來(lái)管理,那就調(diào)用 epoll_ctl,要?jiǎng)h除一個(gè) socket 也調(diào)用 epoll_ctl,通過(guò)不同的入?yún)?lái)控制增刪改。

這樣,在內(nèi)核里面就維護(hù)了此 epoll 管理的 socket 集合,這樣就不用每次調(diào)用的時(shí)候都得把所有管理的 fds 拷貝到內(nèi)核了。

對(duì)了,這個(gè) socket 集合是用紅黑樹實(shí)現(xiàn)的。

然后和 select 類似,每個(gè) socket 的睡眠隊(duì)列里都會(huì)加個(gè) entry,當(dāng)每個(gè) socket 來(lái)數(shù)據(jù)之后,同樣也會(huì)調(diào)用 entry 對(duì)應(yīng)的 callback。

與 select 不同的是,引入了一個(gè) ready_list 雙向鏈表,callback 里面會(huì)把當(dāng)前的 socket 加入到 ready_list 然后喚醒 epoll。

這樣被喚醒的 epoll 只需要遍歷 ready_list 即可,這個(gè)鏈表里一定是有數(shù)據(jù)可讀的 socket,相比于 select 就不會(huì)做無(wú)用的遍歷了。

同時(shí)收集到的可讀的 fd 按理是要拷貝到用戶空間的,這里又做了個(gè)優(yōu)化,利用了 mmp,讓用戶空間和內(nèi)核空間映射到同一塊內(nèi)存中,這樣就避免了拷貝。

完美啊~

這就是 epoll 基于 select 所作的優(yōu)化,還有一些差別沒(méi)細(xì)說(shuō),比如 epoll 是阻塞睡眠在一個(gè) single_epoll_wait_list 而不是 socket 的睡眠隊(duì)列等等,我就不提了,理解上面的這些已經(jīng)夠了。

ET&LT

都談到 epoll 了,避免不了要扯扯 ET 和 LT 兩個(gè)模式。

ET,邊沿觸發(fā)。

按照上面的邏輯就是 epoll 遍歷 ready_list 的時(shí)候,會(huì)把 socket 從 ready_list 里面移除,然后讀取這個(gè) scoket 的事件。

而 LT,水平觸發(fā),有點(diǎn)不一樣。

在這個(gè)模式下 epoll 遍歷 ready_list 的時(shí)候,會(huì)把 socket 從 ready_list 里面移除,然后讀取這個(gè) scoket 的事件,如果這個(gè) socket 返回了感興趣的事件,那么當(dāng)前這個(gè) socket 會(huì)再被加入到 ready_list 中,這樣下次調(diào)用 epoll_wait 的時(shí)候,還能拿到這個(gè) socket。

這就是這兩者最本質(zhì)的區(qū)別了。

看到這有人會(huì)問(wèn),這兩種模式的使用會(huì)造成哪種不一樣的結(jié)果?

如果此時(shí)一個(gè)客戶端同時(shí)發(fā)來(lái)了 5 個(gè)數(shù)據(jù)包,按正常的邏輯,只需要喚醒一次 epoll ,把當(dāng)前 socket 加一次到 ready_list 就行了,不需要加 5 次。然后用戶程序可以把 socket 接收隊(duì)列的所有數(shù)據(jù)包都讀完。

但假設(shè)用戶程序就讀了一個(gè)包,然后處理報(bào)錯(cuò)了,后面不讀了,那后面的 4 個(gè)包咋辦?

如果是 ET 模式,就讀不了了,因?yàn)闆](méi)有把 socket 加入到 ready_list 的觸發(fā)條件了。除非這個(gè)客戶端發(fā)了新的數(shù)據(jù)包過(guò)來(lái),這樣才會(huì)再把當(dāng)前 socket 加入到 ready_list,在新包過(guò)來(lái)之前,這 4 個(gè)數(shù)據(jù)包都不會(huì)被讀到。

而 LT 模式不一樣,因?yàn)槊看巫x完有感興趣的事件發(fā)生之后,會(huì)把當(dāng)前 socket 再加入到 ready_list,所以下次肯定能讀到這個(gè) socket,所以后面的 4 個(gè)數(shù)據(jù)包會(huì)被訪問(wèn)到,不論客戶端是否發(fā)送新包。

至此,我想你應(yīng)該理解什么是 ET ,什么是 LT 了,而不用對(duì)著一些什么狀態(tài)變更觸發(fā)這些不易理解的名詞而發(fā)暈。

最后

好了,今天的分析到此完畢,我個(gè)人覺(jué)得對(duì) select/poll/epoll 的理解到這個(gè)程度就差不多了,當(dāng)然還有很多細(xì)節(jié),需要自行去看源碼探究,問(wèn)我我也不懂,這些都是閱讀網(wǎng)上的源碼分析文章得出的結(jié)論。

我也不建議讀的那么深,畢竟人的精力有限對(duì)吧,有涉及到相關(guān)底層優(yōu)化的時(shí)候,再去研究也不遲。

我是yes,從一點(diǎn)點(diǎn)到億點(diǎn)點(diǎn),我們下篇見。

參考:

https://blog.csdn.net/dog250/article/details/105896693(select真的受1024限制嗎?)

https://blog.csdn.net/dog250/article/details/50528373


責(zé)任編輯:武曉燕 來(lái)源: yes的練級(jí)攻略
相關(guān)推薦

2020-11-04 07:49:04

Select

2024-07-05 11:01:13

2019-07-31 15:56:57

Jvm虛擬機(jī)Content

2022-04-07 13:02:53

前端緩存

2021-05-31 06:50:47

SelectPoll系統(tǒng)

2025-01-07 00:07:17

2020-09-09 12:55:28

Nginx高并發(fā)性能

2020-09-10 09:31:34

Nginx HTTP代理服務(wù)器

2022-06-03 10:52:55

selectpolepoll

2018-10-12 09:42:00

分布式鎖 Java多線

2024-09-27 13:09:30

2020-07-20 10:20:30

this前端代碼

2025-04-21 04:00:00

2022-09-19 18:49:01

偵聽器異步組件

2022-07-01 13:38:48

霧計(jì)算邊緣計(jì)算

2024-01-03 13:39:00

JS,Javascrip算法

2023-10-18 10:55:55

HashMap

2025-04-11 05:55:00

2025-01-13 16:00:00

服務(wù)網(wǎng)關(guān)分布式系統(tǒng)架構(gòu)

2022-05-27 08:18:00

HashMapHash哈希表
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 黄色一级大片在线免费看产 | 国产91在线 | 中日 | 欧美视频中文字幕 | 婷婷国产一区 | 一本色道精品久久一区二区三区 | 国内在线视频 | 最新国产福利在线 | av免费在线观看网站 | 人人九九| 91色综合 | 中文字幕亚洲欧美日韩在线不卡 | 午夜视频在线免费观看 | 久久久成人免费视频 | 国产ts人妖另类 | www国产亚洲精品 | 欧美天堂 | 蜜桃日韩| 超碰97人人人人人蜜桃 | 国产精品精品视频一区二区三区 | 色狠狠一区 | 国产91在线视频 | 午夜免费网站 | 国产区在线看 | 久久久久亚洲 | 中文字幕日韩欧美一区二区三区 | re久久 | 色在线免费 | 在线观看涩涩视频 | 国产a级黄色录像 | 国产一区二区三区视频 | 久久亚洲一区二区 | 国产成人99久久亚洲综合精品 | 国产一级精品毛片 | 亚洲成av人影片在线观看 | 久久久久国产精品一区二区 | 亚洲国产欧美在线人成 | 日韩一区二区三区精品 | hitomi一区二区三区精品 | 国产视频久 | 视频一区二区在线观看 | 精品国产一区一区二区三亚瑟 |