国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

一篇文章帶你徹底搞懂NIO

ziwenxie / 3501人閱讀

摘要:阻塞當(dāng)進(jìn)行讀寫(xiě)時(shí),線程是阻塞的狀態(tài)。當(dāng)任何一個(gè)收到數(shù)據(jù)后,中斷程序?qū)酒疬M(jìn)程。接收數(shù)據(jù)當(dāng)收到數(shù)據(jù)后,中斷程序會(huì)給的就緒列表添加引用。當(dāng)接收到數(shù)據(jù),中斷程序一方面修改,另一方面喚醒等待隊(duì)列中的進(jìn)程,進(jìn)程再次進(jìn)入運(yùn)行狀態(tài)如下圖。

本篇文章目的在于基本概念和原理的解釋,不會(huì)貼過(guò)多的使用代碼。

什么是NIO
Java NIO (New IO)是 Java 的另一個(gè) IO API (來(lái)自 java1.4) ,意味著可以替代標(biāo)準(zhǔn)的 Java IO API和 Java Networking API。 提供了一種與標(biāo)準(zhǔn) IO API 不同的 IO 工作方式。

注意:Java的NIO只是說(shuō)IO API,阻塞非阻塞才是IO的模型。

也有人稱NIO為No-Blocking IO,非阻塞IO,但是這么說(shuō)并不嚴(yán)謹(jǐn)。因?yàn)閷?duì)于基礎(chǔ)的IO操作API(比如文件IO,F(xiàn)ileChannel),還是阻塞的模型。只有對(duì)Networking IO API才可以使用非阻塞的模型(configureBlocking(false))。

Java NIO中的Networking IO API,支持非阻塞IO模型,還實(shí)現(xiàn)了IO多路復(fù)用(IO Multiplexing)。對(duì)于服務(wù)端來(lái)說(shuō),可以用更少的線程支持更多的并發(fā),大幅度提升了性能。

NIO中的阻塞與非阻塞

阻塞與非阻塞是從線程的角度出發(fā)的,這里指的是線程狀態(tài)。

阻塞

當(dāng)進(jìn)行IO讀寫(xiě)時(shí),線程是阻塞的狀態(tài)。此時(shí)會(huì)讓出cpu控制權(quán),不會(huì)占用cpu資源。

什么?不占用CPU資源?那是不是代表阻塞模型更好呢?

答案是并不是,雖然阻塞狀態(tài)不會(huì)占用CPU,但是會(huì)發(fā)生線程的切換,線程切換時(shí)會(huì)有上下文保存轉(zhuǎn)換的過(guò)程,需要CPU調(diào)度,是一個(gè)很昂貴的操作。

Java NIO中的基礎(chǔ)IO API(非Networking IO API)還是阻塞的方式,只是使用方式從面向流(stream)編程面向塊(buffer)了,和BIO本質(zhì)上并沒(méi)有什么區(qū)別。

非阻塞

非阻塞是指在進(jìn)行IO操作的時(shí)候,如果設(shè)備還未準(zhǔn)備好(比如socket還沒(méi)有收到數(shù)據(jù)),操作會(huì)直接返回結(jié)果,不會(huì)讓當(dāng)前線程進(jìn)入阻塞狀態(tài)。

這樣的優(yōu)點(diǎn)是,使用者可以自行決定在數(shù)據(jù)未準(zhǔn)備好時(shí)的操作。線程可以在沒(méi)有數(shù)據(jù)期間去執(zhí)行其他操作。
Networking API可以配置為非阻塞模型Channel.configureBlocking(false),配合Selector來(lái)實(shí)現(xiàn)多路復(fù)用功能。簡(jiǎn)單的說(shuō)就是一個(gè)Selector監(jiān)聽(tīng)多個(gè)socket io(對(duì)于unix系統(tǒng)來(lái)說(shuō),socket也是一個(gè)fd,也屬于io),可以在一個(gè)線程中支持多個(gè)連接。當(dāng)然在實(shí)際服務(wù)器開(kāi)發(fā)時(shí),就算是NIO模型,有些程序也不會(huì)只使用一個(gè)線程;但相比傳統(tǒng)的Blocking IO方式來(lái)說(shuō),需要的線程數(shù)量也會(huì)大大減少了。(redis中就是使用了IO多路復(fù)用技術(shù),并且只有一個(gè)線程監(jiān)聽(tīng)socket io)

AIO

AIO 是 Java 1.7 之后引入的包,是 NIO 的升級(jí)版本,新增了提異步非阻塞的 IO 操作方式,所以人們叫它 AIO(Asynchronous IO),異步 IO 是基于事件和回調(diào)機(jī)制實(shí)現(xiàn)的,也就是應(yīng)用操作之后會(huì)直接返回,不會(huì)堵塞在那里,當(dāng)后臺(tái)處理完成,操作系統(tǒng)會(huì)執(zhí)行回調(diào)通知相應(yīng)的線程進(jìn)行后續(xù)的操作。

多路復(fù)用

在I/O編程過(guò)程中,當(dāng)需要同時(shí)處理多個(gè)客戶端請(qǐng)求時(shí),可以利用多線程或者I/O多路復(fù)用技術(shù)進(jìn)行處理。I/O多路復(fù)用技術(shù)通過(guò)把多個(gè)I/O的阻塞復(fù)用到同一個(gè)Select的阻塞上,從而使得系統(tǒng)在單線程的情況下可以同時(shí)處理多個(gè)客戶端請(qǐng)求。與傳統(tǒng)的多線程/多進(jìn)程模型相比,I/O多路復(fù)用的最大優(yōu)勢(shì)是系統(tǒng)開(kāi)銷小,系統(tǒng)不需要?jiǎng)?chuàng)建新的額外進(jìn)程或者線程,也不需要維護(hù)這些線程和進(jìn)程的運(yùn)行,降低了系統(tǒng)的維護(hù)工作量,節(jié)省了系統(tǒng)的資源,I/O多路復(fù)用的主要應(yīng)用場(chǎng)景如下:

服務(wù)器需要同時(shí)處理多個(gè)處于監(jiān)聽(tīng)狀態(tài)或者多個(gè)連接狀態(tài)的Socket

服務(wù)器需要同時(shí)處理多種網(wǎng)絡(luò)協(xié)議的Socket

目前支持I/O多路復(fù)用的系統(tǒng)調(diào)用又select/pselect/poll/epoll。

select/epoll select

select的實(shí)現(xiàn)思路很直接。假如程序同時(shí)監(jiān)視如下圖的sock1、sock2和sock3三個(gè)socket,那么在調(diào)用select之后,操作系統(tǒng)把進(jìn)程A分別加入這三個(gè)socket的等待隊(duì)列中。

當(dāng)任何一個(gè)socket收到數(shù)據(jù)后,中斷程序?qū)酒疬M(jìn)程。下圖展示了sock2接收到了數(shù)據(jù)的處理流程。

所謂喚起進(jìn)程,就是將進(jìn)程從所有的等待隊(duì)列中移除,加入到工作隊(duì)列里面。如下圖所示。

經(jīng)由這些步驟,當(dāng)進(jìn)程A被喚醒后,它知道至少有一個(gè)socket接收了數(shù)據(jù)。程序只需遍歷一遍socket列表,就可以得到就緒的socket。

這種簡(jiǎn)單方式行之有效,在幾乎所有操作系統(tǒng)都有對(duì)應(yīng)的實(shí)現(xiàn)。

但是簡(jiǎn)單的方法往往有缺點(diǎn),主要是:

其一,每次調(diào)用select都需要將進(jìn)程加入到所有監(jiān)視socket的等待隊(duì)列,每次喚醒都需要從每個(gè)隊(duì)列中移除。這里涉及了兩次遍歷,而且每次都要將整個(gè)fds列表傳遞給內(nèi)核,有一定的開(kāi)銷。正是因?yàn)楸闅v操作開(kāi)銷大,出于效率的考量,才會(huì)規(guī)定select的最大監(jiān)視數(shù)量,默認(rèn)只能監(jiān)視1024個(gè)socket。

其二,進(jìn)程被喚醒后,程序并不知道哪些socket收到數(shù)據(jù),還需要遍歷一次。

那么,有沒(méi)有減少遍歷的方法?有沒(méi)有保存就緒socket的方法?這兩個(gè)問(wèn)題便是epoll技術(shù)要解決的。

補(bǔ)充說(shuō)明: 本節(jié)只解釋了select的一種情形。當(dāng)程序調(diào)用select時(shí),內(nèi)核會(huì)先遍歷一遍socket,如果有一個(gè)以上的socket接收緩沖區(qū)有數(shù)據(jù),那么select直接返回,不會(huì)阻塞。這也是為什么select的返回值有可能大于1的原因之一。如果沒(méi)有socket有數(shù)據(jù),進(jìn)程才會(huì)阻塞。

select低效的原因之一是將“維護(hù)等待隊(duì)列”和“阻塞進(jìn)程”兩個(gè)步驟合二為一。如下圖所示,每次調(diào)用select都需要這兩步操作,然而大多數(shù)應(yīng)用場(chǎng)景中,需要監(jiān)視的socket相對(duì)固定,并不需要每次都修改。epoll將這兩個(gè)操作分開(kāi),先用epoll_ctl維護(hù)等待隊(duì)列,再調(diào)用epoll_wait阻塞進(jìn)程。顯而易見(jiàn)的,效率就能得到提升。

select低效的另一個(gè)原因在于程序不知道哪些socket收到數(shù)據(jù),只能一個(gè)個(gè)遍歷。如果內(nèi)核維護(hù)一個(gè)“就緒列表”,引用收到數(shù)據(jù)的socket,就能避免遍歷。如下圖所示,計(jì)算機(jī)共有三個(gè)socket,收到數(shù)據(jù)的sock2和sock3被rdlist(就緒列表)所引用。當(dāng)進(jìn)程被喚醒后,只要獲取rdlist的內(nèi)容,就能夠知道哪些socket收到數(shù)據(jù)。

epoll

epoll是在select出現(xiàn)N多年后才被發(fā)明的,是select和poll的增強(qiáng)版本。epoll通過(guò)以下一些措施來(lái)改進(jìn)效率。

原理:

創(chuàng)建epoll對(duì)象

如下圖所示,當(dāng)某個(gè)進(jìn)程調(diào)用epoll_create方法時(shí),內(nèi)核會(huì)創(chuàng)建一個(gè)eventpoll對(duì)象(也就是程序中epfd所代表的對(duì)象)。eventpoll對(duì)象也是文件系統(tǒng)中的一員,和socket一樣,它也會(huì)有等待隊(duì)列。

創(chuàng)建一個(gè)代表該epoll的eventpoll對(duì)象是必須的,因?yàn)閮?nèi)核要維護(hù)“就緒列表”等數(shù)據(jù),“就緒列表”可以作為eventpoll的成員。

維護(hù)監(jiān)視列表

創(chuàng)建epoll對(duì)象后,可以用epoll_ctl添加或刪除所要監(jiān)聽(tīng)的socket。以添加socket為例,如下圖,如果通過(guò)epoll_ctl添加sock1、sock2和sock3的監(jiān)視,內(nèi)核會(huì)將eventpoll添加到這三個(gè)socket的等待隊(duì)列中。

當(dāng)socket收到數(shù)據(jù)后,中斷程序會(huì)操作eventpoll對(duì)象,而不是直接操作進(jìn)程。

接收數(shù)據(jù)

當(dāng)socket收到數(shù)據(jù)后,中斷程序會(huì)給eventpoll的“就緒列表”添加socket引用。如下圖展示的是sock2和sock3收到數(shù)據(jù)后,中斷程序讓rdlist引用這兩個(gè)socket。

eventpoll對(duì)象相當(dāng)于是socket和進(jìn)程之間的中介,socket的數(shù)據(jù)接收并不直接影響進(jìn)程,而是通過(guò)改變eventpoll的就緒列表來(lái)改變進(jìn)程狀態(tài)。

當(dāng)程序執(zhí)行到epoll_wait時(shí),如果rdlist已經(jīng)引用了socket,那么epoll_wait直接返回,如果rdlist為空,阻塞進(jìn)程。

阻塞和喚醒進(jìn)程

假設(shè)計(jì)算機(jī)中正在運(yùn)行進(jìn)程A和進(jìn)程B,在某時(shí)刻進(jìn)程A運(yùn)行到了epoll_wait語(yǔ)句。如下圖所示,內(nèi)核會(huì)將進(jìn)程A放入eventpoll的等待隊(duì)列中,阻塞進(jìn)程。

當(dāng)socket接收到數(shù)據(jù),中斷程序一方面修改rdlist,另一方面喚醒eventpoll等待隊(duì)列中的進(jìn)程,進(jìn)程A再次進(jìn)入運(yùn)行狀態(tài)(如下圖)。也因?yàn)閞dlist的存在,進(jìn)程A可以知道哪些socket發(fā)生了變化。

參考

Netty權(quán)威指南

https://zhuanlan.zhihu.com/p/...

http://tutorials.jenkov.com/j...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/75498.html

相關(guān)文章

  • ES6指北【3】——5000字長(zhǎng)文帶你徹底搞懂ES6模塊

    摘要:模塊什么是模塊什么是模塊化玩過(guò)游戲的朋友應(yīng)該知道,一把裝配完整的步槍,一般是槍身消音器倍鏡握把槍托。更重要的是,其它大部分語(yǔ)言都支持模塊化。這一點(diǎn)與規(guī)范完全不同。模塊輸出的是值的緩存,不存在動(dòng)態(tài)更新。 1.模塊 1.1 什么是模塊?什么是模塊化? 玩過(guò)FPS游戲的朋友應(yīng)該知道,一把裝配完整的M4步槍,一般是槍身+消音器+倍鏡+握把+槍托。 如果把M4步槍看成是一個(gè)頁(yè)面的話,那么我們可以...

    ygyooo 評(píng)論0 收藏0
  • 以??簡(jiǎn)單易懂??的語(yǔ)言帶你搞懂有監(jiān)督學(xué)習(xí)算法【附Python代碼詳解】機(jī)器學(xué)習(xí)系列之KNN篇

    必須要看的前言 本文風(fēng)格:以??簡(jiǎn)單易懂??的語(yǔ)言帶你徹底搞懂KNN,了解什么是有監(jiān)督學(xué)習(xí)算法。 認(rèn)真看完這篇文章,徹底了解KNN、了解監(jiān)督學(xué)習(xí)算法絕對(duì)是一樣很簡(jiǎn)單的事情。 注:本篇文章非常詳細(xì),同時(shí)我也附加了Python代碼,歡迎收藏后慢慢閱讀。 目錄 必須要看的前言監(jiān)督學(xué)習(xí)算法KNN/K近鄰算法1 算法原理1.1 實(shí)現(xiàn)過(guò)程1.2 距離的確定 2 算法的優(yōu)缺點(diǎn)3 算法的變種3.1 變...

    MoAir 評(píng)論0 收藏0
  • 少啰嗦!分鐘帶你讀懂Java的NIO和經(jīng)典IO的區(qū)別

    摘要:的選擇器允許單個(gè)線程監(jiān)視多個(gè)輸入通道。一旦執(zhí)行的線程已經(jīng)超過(guò)讀取代碼中的某個(gè)數(shù)據(jù)片段,該線程就不會(huì)在數(shù)據(jù)中向后移動(dòng)通常不會(huì)。 1、引言 很多初涉網(wǎng)絡(luò)編程的程序員,在研究Java NIO(即異步IO)和經(jīng)典IO(也就是常說(shuō)的阻塞式IO)的API時(shí),很快就會(huì)發(fā)現(xiàn)一個(gè)問(wèn)題:我什么時(shí)候應(yīng)該使用經(jīng)典IO,什么時(shí)候應(yīng)該使用NIO? 在本文中,將嘗試用簡(jiǎn)明扼要的文字,闡明Java NIO和經(jīng)典IO之...

    Meils 評(píng)論0 收藏0
  • 牛啤~這個(gè)框架被大量使用,騰訊開(kāi)源的RPC框架阿里的Dubbo全靠它

    摘要:分布式高并發(fā)微服務(wù)問(wèn)阿里京東螞蟻等大廠面試真題解析道跳槽漲薪必備精選面試題最新版大廠面試真題集點(diǎn)擊這里免費(fèi)領(lǐng)取點(diǎn)擊這里免費(fèi)領(lǐng)取 估計(jì)很多Java程序員平時(shí)主要的工作就是一些Web系統(tǒng)的業(yè)務(wù)開(kāi)發(fā),對(duì)于服務(wù)端IO程序以及網(wǎng)絡(luò)通信編程做得并不多,但是對(duì)于高級(jí)或者資深程序員來(lái)說(shuō),IO通信以及服務(wù)端編...

    whidy 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<