国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看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ù)用_動力節(jié)點(diǎn)Java學(xué)院整理

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

2020-10-31 23:47動力節(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)度算法并不會考慮某個(gè)線程可能只是為了一個(gè)連接服務(wù)的,它會做大一統(tǒng)的玩法:時(shí)間片到了就執(zhí)行一下,哪怕這個(gè)線程一執(zhí)行就會不得不繼續(xù)睡眠。這樣來回的喚醒、睡眠線程在次數(shù)不多的情況下,是廉價(jià)的,但如果操作系統(tǒng)的線程總數(shù)很多時(shí),它就是昂貴的(被放大了),因?yàn)檫@種技術(shù)性的調(diào)度損耗會影響到線程上執(zhí)行的業(yè)務(wù)代碼的時(shí)間。舉個(gè)例子,這時(shí)大部分擁有不活躍連接的線程就像我們的國企,它們執(zhí)行效率太低了,它總是喚醒就睡眠在做無用功,而它喚醒爭到cpu資源的同時(shí),就意味著處理活躍連接的民企線程減少獲得了cpu的機(jī)會,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ā)下線程會頻繁的睡眠、喚醒,從而影響了cpu的使用效率。

高并發(fā)編程方法當(dāng)然就是把兩個(gè)階段分開處理。即,等待消息準(zhǔn)備好的代碼段,與處理消息的代碼段是分離的。當(dāng)然,這也要求套接字必須是非阻塞的,否則,處理消息的代碼段很容易導(dǎo)致條件不滿足時(shí),所在線程又進(jìn)入了睡眠等待階段。那么問題來了,等待消息準(zhǔn)備好這個(gè)階段怎么實(shí)現(xiàn)?它畢竟還是等待,這意味著線程還是要睡眠的!解決辦法就是,主動查詢,或者讓1個(gè)線程為所有連接而等待!這就是io多路復(fù)用了。多路復(fù)用就是處理等待消息準(zhǔn)備好這件事的,但它可以同時(shí)處理多個(gè)連接!它也可以“等待”,所以它也可能導(dǎo)致線程睡眠,然而這不要緊,因?yàn)樗粚Χ唷⑺梢员O(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為何會替代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í)候會調(diào)用select方法呢?在你認(rèn)為需要找出有報(bào)文到達(dá)的活躍連接時(shí),就應(yīng)該調(diào)用。所以,調(diào)用select在高并發(fā)時(shí)是會被頻繁調(diào)用的。這樣,這個(gè)頻繁調(diào)用的方法就很有必要看看它是否有效率,因?yàn)椋妮p微效率損失都會被“頻繁”二字所放大。它有效率損失嗎?顯而易見,全部待監(jiān)控連接是數(shù)以十萬計(jì)的,返回的只是數(shù)百個(gè)活躍連接,這本身就是無效率的表現(xiàn)。被放大后就會發(fā)現(xiàn),處理并發(fā)上萬個(gè)連接時(shí),select就完全力不從心了。

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

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

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

Java IO復(fù)用_動力節(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的效率高出一大截,而且,它也不會隨著并發(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ù)用_動力節(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,它會在磁盤io完成時(shí)再發(fā)送響應(yīng)。那么,每次epoll_wait都返回這個(gè)“可寫”的、卻無法立刻處理的連接,是否符合用戶預(yù)期呢?

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

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

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 久久伊人网视频 | 91av在线视频播放 | 成人在线小视频 | 中文在线一区二区三区 | 91av在线播放 | 手机看片在线 | 亚洲精品电影在线观看 | 成人午夜视频网 | 亚洲少妇视频 | 国产深夜视频在线观看 | 国产一区欧美 | 夜夜av | 91精品国产乱码久久久久久久久 | 一本大道av伊人久久综合 | 一级色视频 | 欧美日韩在线视频免费 | 色综合久| 成人久久久久久久 | 黄网在线观看 | 自拍一区视频 | 欧美在线小视频 | 91麻豆精品国产91久久久久久久久 | 久久社区 | 中文字幕三区 | 成人一区二区在线 | 国产色秀视频在线观看 | 久久精品一区二区三区四区 | 中文在线一区二区 | 欧美日韩一区二区三区在线观看 | 四虎永久免费影院 | 久久久久久中文字幕 | av入口| 久久亚洲综合 | 黄色免费网站观看 | 欧美区 日韩区 | 国产99久久精品一区二区永久免费 | 国产精品免费精品自在线观看 | 精品少妇一区二区三区 | 欧美人成在线视频 | 精品久久久久国产 | 色婷婷国产精品综合在线观看 |