日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux的open的非组赛,Linux下的非阻塞IO库epoll

發(fā)布時間:2023/12/20 linux 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux的open的非组赛,Linux下的非阻塞IO库epoll 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

今天看到一篇文章,對于epoll講解的非常生動清晰,轉(zhuǎn)載收藏一下,原文請點(diǎn)擊here。

生活中的一個例子

假設(shè)你在大學(xué)中讀書,要等待一個朋友來訪,而這個朋友只知道你在A號樓,但是不知道你具體住在哪里,于是你們約好了在A號樓門口見面。如果你使用的阻塞IO模型來處理這個問題,那么你就只能一直守候在A號樓門口等待朋友的到來,在這段時間里你不能做別的事情,不難知道,這種方式的效率是低下的。

進(jìn)一步解釋select和epoll模型的差異。select版大媽做的是如下的事情:比如同學(xué)甲的朋友來了,select版大媽比較笨,她帶著朋友挨個房間進(jìn)行查詢誰是同學(xué)甲,你等的朋友來了,于是在實(shí)際的代碼中,select版大媽做的是以下的事情:int n = select(&readset, NULL, NULL, 100);

for (int i = 0; n > 0; ++i) {

if (FD_ISSET(fdarray[i], &readset)) {

do_something(fdarray[i]); --n;

}

}

epoll版大媽就比較先進(jìn)了,她記下了同學(xué)甲的信息,比如說他的房間號,那么等同學(xué)甲的朋友到來時,只需要告訴該朋友同學(xué)甲在哪個房間即可,不用自己親自帶著人滿大樓的找人了,于是epoll版大媽做的事情可以用如下的代碼表示:n = epoll_wait(epfd, events, 20, 500);

for(i=0;i

}

在epoll中,關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)epoll_event定義如下:typedef union epoll_data {

void *ptr;

int fd;

__uint32_t u32;

__uint64_t u64;

}epoll_data_t;

struct epoll_event {

__uint32_t events; /* Epoll events */

epoll_data_t data;/* User data variable */

};

可以看到,epoll_data是一個union結(jié)構(gòu)體,它就是epoll版大媽用于保存同學(xué)信息的結(jié)構(gòu)體,它可以保存很多類型的信息:fd,指針,等等。有了這個結(jié)構(gòu)體,epoll大媽可以不用吹灰之力就可以定位到同學(xué)甲。

別小看了這些效率的提高,在一個大規(guī)模并發(fā)的服務(wù)器中,輪詢IO是最耗時間的操作之一。再回到那個例子中,如果每到來一個朋友樓管大媽都要全樓的查詢同學(xué),那么處理的效率必然就低下了,過不久樓底就有不少的人了。

對比最早給出的阻塞IO的處理模型,可以看到采用了多路復(fù)用IO之后,程序可以自由的進(jìn)行自己除了IO操作之外的工作,只有到IO狀態(tài)發(fā)生變化的時候由多路復(fù)用IO進(jìn)行通知,然后再采取相應(yīng)的操作,而不用一直阻塞等待IO狀態(tài)發(fā)生變化了。

從上面的分析也可以看出,epoll比select的提高實(shí)際上是一個用空間換時間思想的具體應(yīng)用。

深入理解epoll的實(shí)現(xiàn)原理

開發(fā)高性能網(wǎng)絡(luò)程序時,windows開發(fā)者們言必稱iocp,linux開發(fā)者們則言必稱epoll。大家都明白epoll是一種IO多路復(fù)用技術(shù),可以非常高效的處理數(shù)以百萬計的socket句柄,比起以前的select和poll效率高大發(fā)了。我們用起epoll來都感覺挺爽,確實(shí)快,那么,它到底為什么可以高速處理這么多并發(fā)連接呢?先簡單回顧下如何使用C庫封裝的3個epoll系統(tǒng)調(diào)用吧。int epoll_create(int size);

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

int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);

使用起來很清晰,首先要調(diào)用epoll_create建立一個epoll對象。參數(shù)size是內(nèi)核保證能夠正確處理的最大句柄數(shù),多于這個最大數(shù)時內(nèi)核可不保證效果。epoll_ctl可以操作上面建立的epoll,例如,將剛建立的socket加入到epoll中讓其監(jiān)控,或者把 epoll正在監(jiān)控的某個socket句柄移出epoll,不再監(jiān)控它等等。epoll_wait在調(diào)用時,在給定的timeout時間內(nèi),當(dāng)在監(jiān)控的所有句柄中有事件發(fā)生時,就返回用戶態(tài)的進(jìn)程。

從上面的調(diào)用方式就可以看到epoll比select/poll的優(yōu)越之處:

因?yàn)楹笳呙看握{(diào)用時都要傳遞你所要監(jiān)控的所有socket給select/poll系統(tǒng)調(diào)用,這意味著需要將用戶態(tài)的socket列表copy到內(nèi)核態(tài),如果以萬計的句柄會導(dǎo)致每次都要copy幾十幾百KB的內(nèi)存到內(nèi)核態(tài),非常低效。而我們調(diào)用epoll_wait時就相當(dāng)于以往調(diào)用select/poll,但是這時卻不用傳遞socket句柄給內(nèi)核,因?yàn)閮?nèi)核已經(jīng)在epoll_ctl中拿到了要監(jiān)控的句柄列表。

所以,實(shí)際上在你調(diào)用epoll_create后,內(nèi)核就已經(jīng)在內(nèi)核態(tài)開始準(zhǔn)備幫你存儲要監(jiān)控的句柄了,每次調(diào)用epoll_ctl只是在往內(nèi)核的數(shù)據(jù)結(jié)構(gòu)里塞入新的socket句柄。

在內(nèi)核里,一切皆文件。所以,epoll向內(nèi)核注冊了一個文件系統(tǒng),用于存儲上述的被監(jiān)控socket。當(dāng)你調(diào)用epoll_create時,就會在這個虛擬的epoll文件系統(tǒng)里創(chuàng)建一個file結(jié)點(diǎn)。當(dāng)然這個file不是普通文件,它只服務(wù)于epoll。epoll在被內(nèi)核初始化時(操作系統(tǒng)啟動),同時會開辟出epoll自己的內(nèi)核高速cache區(qū),用于安置每一個我們想監(jiān)控的socket,這些socket會以紅黑樹的形式保存在內(nèi)核cache里,以支持快速的查找、插入、刪除。這個內(nèi)核高速cache區(qū),就是建立連續(xù)的物理內(nèi)存頁,然后在之上建立slab層,簡單的說,就是物理上分配好你想要的size的內(nèi)存對象,每次使用時都是使用空閑的已分配好的對象。static int __init eventpoll_init(void) {

... ...

/* Allocates slab cache used to allocate "struct epitem" items */

epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem), 0, SLAB_HWCACHE_ALIGN| EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL);

/* Allocates slab cache used to allocate "struct eppoll_entry" */

pwq_cache = kmem_cache_create("eventpoll_pwq", sizeof(struct eppoll_entry), 0, EPI_SLAB_DEBUG|SLAB_PANIC, NULL, NULL);

... ...

epoll的高效就在于,當(dāng)我們調(diào)用epoll_ctl往里塞入百萬個句柄時,epoll_wait仍然可以飛快的返回,并有效的將發(fā)生事件的句柄給我們用戶。

這是由于我們在調(diào)用epoll_create時,內(nèi)核除了幫我們在epoll文件系統(tǒng)里建了個file結(jié)點(diǎn),在內(nèi)核cache里建了個紅黑樹用于存儲以后epoll_ctl傳來的socket外,還會再建立一個list鏈表,用于存儲準(zhǔn)備就緒的事件,當(dāng)epoll_wait調(diào)用時,僅僅觀察這個list鏈表里有沒有數(shù)據(jù)即可。有數(shù)據(jù)就返回,沒有數(shù)據(jù)就sleep,等到timeout時間到后即使鏈表沒數(shù)據(jù)也返回。所以,epoll_wait非常高效。

那么,這個準(zhǔn)備就緒list鏈表是怎么維護(hù)的呢?當(dāng)我們執(zhí)行epoll_ctl時,除了把socket放到epoll文件系統(tǒng)里file對象對應(yīng)的紅黑樹上之外,還會給內(nèi)核中斷處理程序注冊一個回調(diào)函數(shù),告訴內(nèi)核,如果這個句柄的中斷到了,就把它放到準(zhǔn)備就緒list鏈表里。所以,當(dāng)一個socket上有數(shù)據(jù)到了,內(nèi)核在把網(wǎng)卡上的數(shù)據(jù)copy到內(nèi)核中后就來把socket插入到準(zhǔn)備就緒

鏈表里了。

如此,一顆紅黑樹,一張準(zhǔn)備就緒句柄鏈表,少量的內(nèi)核cache,就幫我們解決了大并發(fā)下的socket處理問題。執(zhí)行epoll_create時,創(chuàng)建了紅黑樹和就緒鏈表,執(zhí)行epoll_ctl時,如果增加socket句柄,則檢查在紅黑樹中是否存在,存在立即返回,不存在則添加到樹干上,然后向內(nèi)核注冊回調(diào)函數(shù),用于當(dāng)中斷事件來臨時向準(zhǔn)備就緒鏈表中插入數(shù)據(jù)。執(zhí)行epoll_wait時立刻返回準(zhǔn)備就緒鏈表里的數(shù)據(jù)即可。

最后看看epoll獨(dú)有的兩種模式LT和ET。無論是LT和ET模式,都適用于以上所說的流程。區(qū)別是,LT模式下,只要一個句柄上的事件一次沒有處理完,會在以后調(diào)用epoll_wait時次次返回這個句柄,而ET模式僅在第一次返回。

這件事怎么做到的呢?當(dāng)一個socket句柄上有事件時,內(nèi)核會把該句柄插入上面所說的準(zhǔn)備就緒list鏈表,這時我們調(diào)用epoll_wait,會把準(zhǔn)備就緒的socket拷貝到用戶態(tài)內(nèi)存,然后清空準(zhǔn)備就緒list鏈表,最后,epoll_wait干了件事,就是檢查這些socket,如果不是ET模式(就是LT模式的句柄了),并且這些socket上確實(shí)有未處理的事件時,又把該句柄放回到剛剛清空的準(zhǔn)備就緒鏈表了。

所以,非ET的句柄,只要它上面還有事件,epoll_wait每次都會返回。而ET模式的句柄,除非有新中斷到,即使socket上的事件沒有處理完,也是不會次次從epoll_wait返回的。

擴(kuò)展閱讀

Linux提供了select、poll、epoll接口來實(shí)現(xiàn)IO復(fù)用,三者的原型如下所示,本文從參數(shù)、實(shí)現(xiàn)、性能等方面對三者進(jìn)行對比。int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

int poll(struct pollfd *fds, nfds_t nfds, int timeout);

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);

select、poll、epoll_wait參數(shù)及實(shí)現(xiàn)對比:

select的第一個參數(shù)nfds為fdset集合中最大描述符值加1,fdset是一個位數(shù)組,其大小限制為__FD_SETSIZE(1024),位數(shù)組的每一位代表其對應(yīng)的描述符是否需要被檢查。

select的第二三四個參數(shù)表示需要關(guān)注讀、寫、錯誤事件的文件描述符位數(shù)組,這些參數(shù)既是輸入?yún)?shù)也是輸出參數(shù),可能會被內(nèi)核修改用于標(biāo)示哪些描述符上發(fā)生了關(guān)注的事件。

所以每次調(diào)用select前都需要重新初始化fdset。

timeout參數(shù)為超時時間,該結(jié)構(gòu)會被內(nèi)核修改,其值為超時剩余的時間。

select對應(yīng)于內(nèi)核中的sys_select調(diào)用,sys_select首先將第二三四個參數(shù)指向的fd_set拷貝到內(nèi)核,然后對每個被SET的描述符調(diào)用進(jìn)行poll,并記錄在臨時結(jié)果中(fdset),如果有事件發(fā)生,select會將臨時結(jié)果寫到用戶空間并返回;當(dāng)輪詢一遍后沒有任何事件發(fā)生時,如果指定了超時時間,則select會睡眠到超時,睡眠結(jié)束后再進(jìn)行一次輪詢,并將臨時結(jié)果寫到用戶空間,然后返回。 select返回后,需要逐一檢查關(guān)注的描述符是否被SET(事件是否發(fā)生)。

poll與select不同,通過一個pollfd數(shù)組向內(nèi)核傳遞需要關(guān)注的事件,故沒有描述符個數(shù)的限制,pollfd中的events字段和revents分別用于標(biāo)示關(guān)注的事件和發(fā)生的事件,故pollfd數(shù)組只需要被初始化一次。

poll的實(shí)現(xiàn)機(jī)制與select類似,其對應(yīng)內(nèi)核中的sys_poll,只不過poll向內(nèi)核傳遞pollfd數(shù)組,然后對pollfd中的每個描述符進(jìn)行poll,相比處理fdset來說,poll效率更高。 poll返回后,需要對pollfd中的每個元素檢查其revents值,來得指事件是否發(fā)生。

epoll通過epoll_create創(chuàng)建一個用于epoll輪詢的描述符,通過epoll_ctl添加/修改/刪除事件,通過epoll_wait檢查事件,epoll_wait的第二個參數(shù)用于存放結(jié)果。 epoll與select、poll不同,首先,其不用每次調(diào)用都向內(nèi)核拷貝事件描述信息,在第一次調(diào)用后,事件信息就會與對應(yīng)的epoll描述符關(guān)聯(lián)起來。另外epoll不是通過輪詢,而是通過在等待的描述符上注冊回調(diào)函數(shù),當(dāng)事件發(fā)生時,回調(diào)函數(shù)負(fù)責(zé)把發(fā)生的事件存儲在就緒事件鏈表中,最后寫到用戶空間。

更多關(guān)于select的知識可參考我之前的博客《select(pselect)函數(shù)》。

總結(jié)

以上是生活随笔為你收集整理的linux的open的非组赛,Linux下的非阻塞IO库epoll的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 欧美黄色片网站 | 日韩二区视频 | 亚洲男人的天堂在线 | 青青草视频国产 | 人妻巨大乳hd免费看 | 精品综合网 | 日韩精品视频一区二区 | 182午夜视频 | 亚洲欧洲免费视频 | 国产在线黄色 | 黑人一级视频 | 久久免费在线 | 国内自拍网站 | 日韩一区二区三区在线看 | 中文字幕欧美色图 | 精品少妇人妻av免费久久久 | 神马午夜电影一区二区三区在线观看 | www.97色| 全部毛片永久免费看 | 视频在线不卡 | 韩国激情呻吟揉捏胸视频 | 中文字幕亚洲激情 | 色乱码一区二区三在线看 | 免费看一区二区三区 | 2025国产精品视频 | 快乐激情网 | 精品中文字幕一区 | 午夜不卡在线观看 | 激情婷婷六月天 | 成人久久一区 | 亚洲成人欧美 | 亚洲国产免费看 | 成人一二区 | 性生交大片免费看女人按摩 | 欧美极品jizzhd欧美爆 | 日本黄区免费视频观看 | 九色影院 | 男人与雌性宠物交啪啪 | 97成人精品视频在线观看 | 蜜桃tv一区二区三区 | 在线观看免费 | 欧美顶级黄色大片免费 | 久久另类ts人妖一区二区 | 国产原创精品 | 日批网站在线观看 | 日本久久久久久 | 香蕉久久国产 | 日本在线精品视频 | 激情av小说 | 色播99 | 天天射天天射 | 免费看av网 | 丝袜美腿av | 美女主播在线观看 | 嫩草影院永久入口 | 日本一区二区三区精品视频 | 亚洲国产精品成人午夜在线观看 | 国内精品久久久久久久久 | 色综合图区 | 8x国产一区二区三区精品推荐 | 97久草| 国产老女人乱淫免费可以 | 熟妇熟女乱妇乱女网站 | 国产大学生av | 欧美亚洲一二三区 | 超碰国产在线观看 | 91 免费看片| 少妇高潮一69aⅹ | 性奶老妇 视频 | 欧美真人性野外做爰 | 国产成人在线影院 | 精品久久免费 | 97成人在线 | 久久美利坚 | 一本大道熟女人妻中文字幕在线 | 亚洲黄a | 狠狠人妻久久久久久综合麻豆 | 亚洲妇女无套内射精 | 日韩美女啪啪 | 精品视频在线免费 | 亚洲综合福利 | 黄视频网站在线 | 国产同性人妖ts口直男 | avt天堂网 | 国产人澡人澡澡澡人碰视频 | 国产午夜精品一区二区理论影院 | 亚洲熟妇丰满大屁股熟妇 | 色婷婷激情综合 | 小柔的淫辱日记(1~7) | www.youjizz.com国产| 欧美色图888 | 999国产精品 | 欧美3p视频 | 久久精品国产亚洲av久 | 五月天激情四射 | 国产a一级 | 操比网站 | 久久久久久久久久一区 | 亚洲精品国产精品乱码不99 |