激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Java IO復(fù)用_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

Java IO復(fù)用_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

2020-10-31 23:47動(dòng)力節(jié)點(diǎn) Java教程

這篇文章主要介紹了Java IO復(fù)用的相關(guān)知識,非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下吧

對于服務(wù)器的并發(fā)處理能力,我們需要的是:每一毫秒服務(wù)器都能及時(shí)處理這一毫秒內(nèi)收到的數(shù)百個(gè)不同tcp連接上的報(bào)文,與此同時(shí),可能服務(wù)器上還有數(shù)以十萬計(jì)的最近幾秒沒有收發(fā)任何報(bào)文的相對不活躍連接。同時(shí)處理多個(gè)并行發(fā)生事件的連接,簡稱為并發(fā);同時(shí)處理萬計(jì)、十萬計(jì)的連接,則是高并發(fā)。服務(wù)器的并發(fā)編程所追求的就是處理的并發(fā)連接數(shù)目無限大,同時(shí)維持著高效率使用cpu等資源,直至物理資源首先耗盡。

并發(fā)編程有很多種實(shí)現(xiàn)模型,最簡單的就是與“線程”捆綁,1個(gè)線程處理1個(gè)連接的全部生命周期。優(yōu)點(diǎn):這個(gè)模型足夠簡單,它可以實(shí)現(xiàn)復(fù)雜的業(yè)務(wù)場景,同時(shí),線程個(gè)數(shù)是可以遠(yuǎn)大于cpu個(gè)數(shù)的。然而,線程個(gè)數(shù)又不是可以無限增大的,為什么呢?因?yàn)榫€程什么時(shí)候執(zhí)行是由操作系統(tǒng)內(nèi)核調(diào)度算法決定的,調(diào)度算法并不會(huì)考慮某個(gè)線程可能只是為了一個(gè)連接服務(wù)的,它會(huì)做大一統(tǒng)的玩法:時(shí)間片到了就執(zhí)行一下,哪怕這個(gè)線程一執(zhí)行就會(huì)不得不繼續(xù)睡眠。這樣來回的喚醒、睡眠線程在次數(shù)不多的情況下,是廉價(jià)的,但如果操作系統(tǒng)的線程總數(shù)很多時(shí),它就是昂貴的(被放大了),因?yàn)檫@種技術(shù)性的調(diào)度損耗會(huì)影響到線程上執(zhí)行的業(yè)務(wù)代碼的時(shí)間。舉個(gè)例子,這時(shí)大部分擁有不活躍連接的線程就像我們的國企,它們執(zhí)行效率太低了,它總是喚醒就睡眠在做無用功,而它喚醒爭到cpu資源的同時(shí),就意味著處理活躍連接的民企線程減少獲得了cpu的機(jī)會(huì),cpu是核心競爭力,它的無效率進(jìn)而影響了gdp總吞吐量。我們所追求的是并發(fā)處理數(shù)十萬連接,當(dāng)幾千個(gè)線程出現(xiàn)時(shí),系統(tǒng)的執(zhí)行效率就已經(jīng)無法滿足高并發(fā)了。

對高并發(fā)編程,目前只有一種模型,也是本質(zhì)上唯一有效的玩法。連接上的消息處理,可以分為兩個(gè)階段:等待消息準(zhǔn)備好、消息處理。當(dāng)使用默認(rèn)的阻塞套接字時(shí)(例如上面提到的1個(gè)線程捆綁處理1個(gè)連接),往往是把這兩個(gè)階段合而為一,這樣操作套接字的代碼所在的線程就得睡眠來等待消息準(zhǔn)備好,這導(dǎo)致了高并發(fā)下線程會(huì)頻繁的睡眠、喚醒,從而影響了cpu的使用效率。

高并發(fā)編程方法當(dāng)然就是把兩個(gè)階段分開處理。即,等待消息準(zhǔn)備好的代碼段,與處理消息的代碼段是分離的。當(dāng)然,這也要求套接字必須是非阻塞的,否則,處理消息的代碼段很容易導(dǎo)致條件不滿足時(shí),所在線程又進(jìn)入了睡眠等待階段。那么問題來了,等待消息準(zhǔn)備好這個(gè)階段怎么實(shí)現(xiàn)?它畢竟還是等待,這意味著線程還是要睡眠的!解決辦法就是,主動(dòng)查詢,或者讓1個(gè)線程為所有連接而等待!這就是io多路復(fù)用了。多路復(fù)用就是處理等待消息準(zhǔn)備好這件事的,但它可以同時(shí)處理多個(gè)連接!它也可以“等待”,所以它也可能導(dǎo)致線程睡眠,然而這不要緊,因?yàn)樗粚Χ?、它可以監(jiān)控所有連接。這樣,當(dāng)我們的線程被喚醒執(zhí)行時(shí),就一定是有一些連接準(zhǔn)備好被我們的代碼執(zhí)行了,這是有效率的!沒有那么多個(gè)線程都在爭搶處理“等待消息準(zhǔn)備好”階段,整個(gè)世界終于清凈了!

多路復(fù)用有很多種實(shí)現(xiàn),在linux上,2.4內(nèi)核前主要是select和poll,現(xiàn)在主流是epoll,它們的使用方法似乎很不同,但本質(zhì)是一樣的。

效率卻也不同,這也是epoll完全替代了select的原因。

簡單的談下epoll為何會(huì)替代select。

前面提到過,高并發(fā)的核心解決方案是1個(gè)線程處理所有連接的“等待消息準(zhǔn)備好”,這一點(diǎn)上epoll和select是無爭議的。但select預(yù)估錯(cuò)誤了一件事,就像我們開篇所說,當(dāng)數(shù)十萬并發(fā)連接存在時(shí),可能每一毫秒只有數(shù)百個(gè)活躍的連接,同時(shí)其余數(shù)十萬連接在這一毫秒是非活躍的。select的使用方法是這樣的:

返回的活躍連接 ==select(全部待監(jiān)控的連接)

什么時(shí)候會(huì)調(diào)用select方法呢?在你認(rèn)為需要找出有報(bào)文到達(dá)的活躍連接時(shí),就應(yīng)該調(diào)用。所以,調(diào)用select在高并發(fā)時(shí)是會(huì)被頻繁調(diào)用的。這樣,這個(gè)頻繁調(diào)用的方法就很有必要看看它是否有效率,因?yàn)?,它的輕微效率損失都會(huì)被“頻繁”二字所放大。它有效率損失嗎?顯而易見,全部待監(jiān)控連接是數(shù)以十萬計(jì)的,返回的只是數(shù)百個(gè)活躍連接,這本身就是無效率的表現(xiàn)。被放大后就會(huì)發(fā)現(xiàn),處理并發(fā)上萬個(gè)連接時(shí),select就完全力不從心了。

看幾個(gè)圖。當(dāng)并發(fā)連接為一千以下,select的執(zhí)行次數(shù)不算頻繁,與epoll似乎并無多少差距:

Java IO復(fù)用_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

然而,并發(fā)數(shù)一旦上去,select的缺點(diǎn)被“執(zhí)行頻繁”無限放大了,且并發(fā)數(shù)越多越明顯:

Java IO復(fù)用_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

再來說說epoll是如何解決的。它很聰明的用了3個(gè)方法來實(shí)現(xiàn)select方法要做的事:

新建的epoll描述符==epoll_create()

epoll_ctrl(epoll描述符,添加或者刪除所有待監(jiān)控的連接)

返回的活躍連接 ==epoll_wait( epoll描述符 )

這么做的好處主要是:分清了頻繁調(diào)用和不頻繁調(diào)用的操作。例如,epoll_ctrl是不太頻繁調(diào)用的,而epoll_wait是非常頻繁調(diào)用的。這時(shí),epoll_wait卻幾乎沒有入?yún)?,這比select的效率高出一大截,而且,它也不會(huì)隨著并發(fā)連接的增加使得入?yún)⒃桨l(fā)多起來,導(dǎo)致內(nèi)核執(zhí)行效率下降。

epoll是怎么實(shí)現(xiàn)的呢?其實(shí)很簡單,從這3個(gè)方法就可以看出,它比select聰明的避免了每次頻繁調(diào)用“哪些連接已經(jīng)處在消息準(zhǔn)備好階段”的 epoll_wait時(shí),是不需要把所有待監(jiān)控連接傳入的。這意味著,它在內(nèi)核態(tài)維護(hù)了一個(gè)數(shù)據(jù)結(jié)構(gòu)保存著所有待監(jiān)控的連接。這個(gè)數(shù)據(jù)結(jié)構(gòu)就是一棵紅黑樹,它的結(jié)點(diǎn)的增加、減少是通過epoll_ctrl來完成的。它是非常簡單的:

Java IO復(fù)用_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

圖中左下方的紅黑樹由所有待監(jiān)控的連接構(gòu)成。左上方的鏈表,同是目前所有活躍的連接。于是,epoll_wait執(zhí)行時(shí)只是檢查左上方的鏈表,并返回左上方鏈表中的連接給用戶。這樣,epoll_wait的執(zhí)行效率能不高嗎?

最后,再看看epoll提供的2種玩法et和lt,即翻譯過來的邊緣觸發(fā)和水平觸發(fā)。其實(shí)這兩個(gè)中文名字倒也有些貼切。這2種使用方式針對的仍然是效率問題,只不過變成了epoll_wait返回的連接如何能夠更準(zhǔn)確些。

例如,我們需要監(jiān)控一個(gè)連接的寫緩沖區(qū)是否空閑,滿足“可寫”時(shí)我們就可以從用戶態(tài)將響應(yīng)調(diào)用write發(fā)送給客戶端 。但是,或者連接可寫時(shí),我們的“響應(yīng)”內(nèi)容還在磁盤上呢,此時(shí)若是磁盤讀取還未完成呢?肯定不能使線程阻塞的,那么就不發(fā)送響應(yīng)了。但是,下一次epoll_wait時(shí)可能又把這個(gè)連接返回給你了,你還得檢查下是否要處理??赡埽覀兊某绦蛴辛硪粋€(gè)模塊專門處理磁盤io,它會(huì)在磁盤io完成時(shí)再發(fā)送響應(yīng)。那么,每次epoll_wait都返回這個(gè)“可寫”的、卻無法立刻處理的連接,是否符合用戶預(yù)期呢?

于是,et和lt模式就應(yīng)運(yùn)而生了。lt是每次滿足期待狀態(tài)的連接,都得在epoll_wait中返回,所以它一視同仁,都在一條水平線上。et則不然,它傾向更精確的返回連接。在上面的例子中,連接第一次變?yōu)榭蓪懞?,若是程序未向連接上寫入任何數(shù)據(jù),那么下一次epoll_wait是不會(huì)返回這個(gè)連接的。et叫做 邊緣觸發(fā),就是指,只有連接從一個(gè)狀態(tài)轉(zhuǎn)到另一個(gè)狀態(tài)時(shí),才會(huì)觸發(fā)epoll_wait返回它??梢?,et的編程要復(fù)雜不少,至少應(yīng)用程序要小心的防止epoll_wait的返回的連接出現(xiàn):可寫時(shí)未寫數(shù)據(jù)后卻期待下一次“可寫”、可讀時(shí)未讀盡數(shù)據(jù)卻期待下一次“可讀”。

當(dāng)然,從一般應(yīng)用場景上它們性能是不會(huì)有什么大的差距的,et可能的優(yōu)點(diǎn)是,epoll_wait的調(diào)用次數(shù)會(huì)減少一些,某些場景下連接在不必要喚醒時(shí)不會(huì)被喚醒(此喚醒指epoll_wait返回)。但如果像我上面舉例所說的,有時(shí)它不單純是一個(gè)網(wǎng)絡(luò)問題,跟應(yīng)用場景相關(guān)。當(dāng)然,大部分開源框架都是基于et寫的,框架嘛,它追求的是純技術(shù)問題,當(dāng)然力求盡善盡美

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 2023av在线视频 | 国产亚洲高清在线精品不卡 | 久草影音 | 欧美性生活久久久 | 日韩激情| 国产欧美日韩视频在线观看 | 激情综合网俺也去 | 国产二三区 | 色综合网在线观看 | 91久久精品一二三区 | 国产精品久久久久久影院8一贰佰 | 黄色av.com| 艹艹艹逼 | 久久国产成人午夜av浪潮 | 亚洲午夜免费电影 | 正在播放91视频 | 久久精品中文字幕一区二区 | 中文黄色一级片 | 久草视频免费 | 国产91久久久久 | 久久精品视频一区 | 久久人人爽人人爽人人片av高请 | 高清av在线 | 国产999精品久久久久 | 成人福利在线免费观看 | 日韩精品网站在线观看 | 91精品国产99久久久久久 | 久久蜜臀一区二区三区av | 欧美一区二区三区久久精品视 | 一区在线免费视频 | 久久777国产线看观看精品 | 日韩在线播放中文字幕 | 欧美激情999 | 国产精品久久久在线观看 | 国产精品美女久久久免费 | 免费国产之a视频 | 精品在线观看一区二区 | 狠狠婷婷综合久久久久久妖精 | 看91视频| 91av在线免费视频 | 国产精品亚洲欧美一级在线 |