欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

 更新時(shí)間:2017年05月27日 10:44:28   投稿:mrr  
這篇文章主要介紹了Java IO復(fù)用的相關(guān)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下吧

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

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

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

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

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

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

前面提到過(guò),高并發(fā)的核心解決方案是1個(gè)線程處理所有連接的“等待消息準(zhǔn)備好”,這一點(diǎn)上epoll和select是無(wú)爭(zhēng)議的。但select預(yù)估錯(cuò)誤了一件事,就像我們開篇所說(shuō),當(dāng)數(shù)十萬(wàn)并發(fā)連接存在時(shí),可能每一毫秒只有數(shù)百個(gè)活躍的連接,同時(shí)其余數(shù)十萬(wàn)連接在這一毫秒是非活躍的。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)椋妮p微效率損失都會(huì)被“頻繁”二字所放大。它有效率損失嗎?顯而易見,全部待監(jiān)控連接是數(shù)以十萬(wàn)計(jì)的,返回的只是數(shù)百個(gè)活躍連接,這本身就是無(wú)效率的表現(xiàn)。被放大后就會(huì)發(fā)現(xiàn),處理并發(fā)上萬(wàn)個(gè)連接時(shí),select就完全力不從心了。
看幾個(gè)圖。當(dāng)并發(fā)連接為一千以下,select的執(zhí)行次數(shù)不算頻繁,與epoll似乎并無(wú)多少差距: 

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

再來(lái)說(shuō)說(shuō)epoll是如何解決的。它很聰明的用了3個(gè)方法來(lái)實(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卻幾乎沒(méi)有入?yún)?,這比select的效率高出一大截,而且,它也不會(huì)隨著并發(fā)連接的增加使得入?yún)⒃桨l(fā)多起來(lái),導(dǎo)致內(nèi)核執(zhí)行效率下降。

epoll是怎么實(shí)現(xiàn)的呢?其實(shí)很簡(jiǎn)單,從這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)的增加、減少是通過(guò)epoll_ctrl來(lái)完成的。它是非常簡(jiǎn)單的: 

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

最后,再看看epoll提供的2種玩法ET和LT,即翻譯過(guò)來(lái)的邊緣觸發(fā)和水平觸發(fā)。其實(shí)這兩個(gè)中文名字倒也有些貼切。這2種使用方式針對(duì)的仍然是效率問(wèn)題,只不過(guò)變成了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è)“可寫”的、卻無(wú)法立刻處理的連接,是否符合用戶預(yù)期呢?

于是,ET和LT模式就應(yīng)運(yùn)而生了。LT是每次滿足期待狀態(tài)的連接,都得在epoll_wait中返回,所以它一視同仁,都在一條水平線上。ET則不然,它傾向更精確的返回連接。在上面的例子中,連接第一次變?yōu)榭蓪懞螅羰浅绦蛭聪蜻B接上寫入任何數(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)用場(chǎng)景上它們性能是不會(huì)有什么大的差距的,ET可能的優(yōu)點(diǎn)是,epoll_wait的調(diào)用次數(shù)會(huì)減少一些,某些場(chǎng)景下連接在不必要喚醒時(shí)不會(huì)被喚醒(此喚醒指epoll_wait返回)。但如果像我上面舉例所說(shuō)的,有時(shí)它不單純是一個(gè)網(wǎng)絡(luò)問(wèn)題,跟應(yīng)用場(chǎng)景相關(guān)。當(dāng)然,大部分開源框架都是基于ET寫的,框架嘛,它追求的是純技術(shù)問(wèn)題,當(dāng)然力求盡善盡美

相關(guān)文章

  • 代碼詳解java里的“==”和“equels”區(qū)別

    代碼詳解java里的“==”和“equels”區(qū)別

    本篇文章通過(guò)實(shí)例代碼給大家詳細(xì)解釋了java里的“==”和“equels”區(qū)別,對(duì)此有興趣的朋友跟著小編一起學(xué)習(xí)下。
    2018-02-02
  • 使用quartz時(shí),傳入?yún)?shù)到j(luò)ob中的使用記錄

    使用quartz時(shí),傳入?yún)?shù)到j(luò)ob中的使用記錄

    這篇文章主要介紹了使用quartz時(shí),傳入?yún)?shù)到j(luò)ob中的使用記錄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • Spring中ClassPathXmlApplicationContext類的使用詳解

    Spring中ClassPathXmlApplicationContext類的使用詳解

    這篇文章主要介紹了Spring中ClassPathXmlApplicationContext類的使用詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • java實(shí)現(xiàn)微信點(diǎn)餐申請(qǐng)微信退款

    java實(shí)現(xiàn)微信點(diǎn)餐申請(qǐng)微信退款

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)微信點(diǎn)餐申請(qǐng)微信退款,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • 一文詳解Java中的可變對(duì)象(Mutable)與不可變對(duì)象(Immutable)

    一文詳解Java中的可變對(duì)象(Mutable)與不可變對(duì)象(Immutable)

    如何在 Java 中創(chuàng)建不可變對(duì)象?我以前以為所有對(duì)象都是不可變的,因?yàn)槿绻愀淖円粋€(gè) String 實(shí)例的內(nèi)容,它總是會(huì)創(chuàng)建一個(gè)新的 String 對(duì)象并指向該對(duì)象,在本文中,我不僅將分享在 Java 中Immutable的步驟,還將討論可變對(duì)象與不可變對(duì)象及其優(yōu)缺點(diǎn)
    2023-11-11
  • Java的Struts2框架中攔截器使用的實(shí)例教程

    Java的Struts2框架中攔截器使用的實(shí)例教程

    攔截器是Struts框架的重要特性,Struts中每一個(gè)Action請(qǐng)求都包裝在一系列的攔截器的內(nèi)部,這里我們就來(lái)看一下Java的Struts2框架中攔截器使用的實(shí)例教程
    2016-07-07
  • JAVA項(xiàng)目字典與緩存搭配使用方法解析

    JAVA項(xiàng)目字典與緩存搭配使用方法解析

    這篇文章主要介紹了JAVA項(xiàng)目字典與緩存搭配使用方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • java 多線程的同步幾種方法

    java 多線程的同步幾種方法

    這篇文章主要介紹了java 多線程的同步幾種方法的相關(guān)資料,這里提供5種方法,需要的朋友可以參考下
    2017-09-09
  • SpringBoot連接MYSQL數(shù)據(jù)庫(kù)并使用JPA進(jìn)行操作

    SpringBoot連接MYSQL數(shù)據(jù)庫(kù)并使用JPA進(jìn)行操作

    今天給大家介紹一下如何SpringBoot中連接Mysql數(shù)據(jù)庫(kù),并使用JPA進(jìn)行數(shù)據(jù)庫(kù)的相關(guān)操作。
    2017-04-04
  • java中Collections.sort排序詳解

    java中Collections.sort排序詳解

    這篇文章主要介紹了java中Collections.sort排序詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-12-12

最新評(píng)論