自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

讓我們一起聊聊IO

存儲(chǔ) 存儲(chǔ)軟件
Java.io包基于流模型實(shí)現(xiàn),提供File抽象、輸入輸出流等IO的功能。交互方式是同步、阻塞的方式,在讀取輸入流或者寫入輸出流時(shí),在讀、寫動(dòng)作完成之前,線程會(huì)一直阻塞。java.io包的好處是代碼比較簡(jiǎn)單、直觀,缺點(diǎn)則是IO效率和擴(kuò)展性存在局限性,容易成為應(yīng)用性能的瓶頸。

 [[419826]]

1.IO模型

IO是Input/Output的縮寫。Linix網(wǎng)絡(luò)編程中有五種IO模型:

  • blocking IO(阻塞IO)
  • nonblocking IO(非阻塞IO)
  • IO multiplexing(多路復(fù)用IO)
  • signal driven IO(信號(hào)驅(qū)動(dòng)IO)
  • asynchronous IO(異步IO)

簡(jiǎn)介

  • Java.io包基于流模型實(shí)現(xiàn),提供File抽象、輸入輸出流等IO的功能。交互方式是同步、阻塞的方式,在讀取輸入流或者寫入輸出流時(shí),在讀、寫動(dòng)作完成之前,線程會(huì)一直阻塞。java.io包的好處是代碼比較簡(jiǎn)單、直觀,缺點(diǎn)則是IO效率和擴(kuò)展性存在局限性,容易成為應(yīng)用性能的瓶頸。
  • Java.net下面提供的部分網(wǎng)絡(luò)API,比如Socket、ServerSocket、HttpURLConnection 也時(shí)常被歸類到同步阻塞IO類庫(kù),網(wǎng)絡(luò)通信同樣是IO行為
  • Java 1.4中引入了NIO框架(java.nio 包),提供了Channel、Selector、Buffer等新的抽象,可以構(gòu)建多路復(fù)用IO程序,同時(shí)提供更接近操作系統(tǒng)底層的高性能數(shù)據(jù)操作方式。
  • Java7中,NIO有了進(jìn)一步的改進(jìn),也就是NIO2,引入了異步非阻塞IO方式,也被稱為AIO(Asynchronous IO),異步IO操作基于事件和回調(diào)機(jī)制。

首先了解下同步\異步、阻塞\非阻塞的區(qū)別

同步與異步

同步和異步是針對(duì)的是用戶進(jìn)程與內(nèi)核的交互方式。

同步指的是用戶進(jìn)程觸發(fā)IO操作并等待或者輪詢的去查看IO操作是否就緒。例如:自己去銀行辦理業(yè)務(wù),自己只能一直干這件事,其他事情只能等這件是做完后再做

異步指的是用戶進(jìn)程觸發(fā)IO操作以后便開始做其他的事情,而當(dāng)IO操作已經(jīng)完成的時(shí)候會(huì)得到IO完成的通知。例如:委托親屬去銀行辦理業(yè)務(wù),然后自己可以去干別的事。(使用異步I/O時(shí),Java將I/O讀寫委托給OS處理,需要將數(shù)據(jù)緩沖區(qū)地址和大小傳給OS)。

阻塞與非阻塞

  • 阻塞和非阻塞是針對(duì)進(jìn)程在訪問數(shù)據(jù)的時(shí)候,根據(jù)IO操作的就緒狀態(tài)來采取的不同方式。
  • 阻塞指的是當(dāng)試圖對(duì)該文件描述符進(jìn)行讀寫時(shí),如果當(dāng)時(shí)沒有東西可讀,或暫時(shí)不可寫,程序就進(jìn)入等待狀態(tài),直到有東西可讀或可寫為止。去辦理業(yè)務(wù)時(shí),人過多需要排隊(duì),此時(shí)就在原地等待,一直等到自己為止。

非阻塞指的是如果沒有東西可讀,或不可寫,讀寫函數(shù)馬上返回,而不會(huì)等待。在銀行里辦業(yè)務(wù)時(shí),領(lǐng)取一張小票,之后我們可以玩手機(jī),或與別人聊聊天,當(dāng)輪到我們時(shí),銀行的喇叭會(huì)通知,這時(shí)候我們就可以去辦業(yè)務(wù)了。

注意,這里辦業(yè)務(wù)的時(shí)候,還是需要我們也參與其中的,這和異步是完全不同的,因此同步\異步、阻塞\非阻塞,是完全不同的兩個(gè)概念,二者不要混淆

I/O模型分類

應(yīng)用程序向操作系統(tǒng)發(fā)出IO請(qǐng)求:應(yīng)用程序發(fā)出IO請(qǐng)求給操作系統(tǒng)內(nèi)核,操作系統(tǒng)內(nèi)核需要等待數(shù)據(jù)就緒,這里的數(shù)據(jù)可能來自別的應(yīng)用程序或者網(wǎng)絡(luò)。一般來說,一個(gè)IO分為兩個(gè)階段:

  1. 等待數(shù)據(jù):數(shù)據(jù)可能來自其他應(yīng)用程序或者網(wǎng)絡(luò),如果沒有數(shù)據(jù),應(yīng)用程序就阻塞等待。
  2. 拷貝數(shù)據(jù):將就緒的數(shù)據(jù)拷貝到應(yīng)用程序工作區(qū)。

在Linux系統(tǒng)中,操作系統(tǒng)的IO操作是一個(gè)系統(tǒng)調(diào)用recvfrom(),即一個(gè)系統(tǒng)調(diào)用recvfrom包含兩步,等待數(shù)據(jù)就緒和拷貝數(shù)據(jù)。

同步阻塞IO

在此種方式下,用戶進(jìn)程在發(fā)起一個(gè)IO操作以后,必須等待IO操作的完成,只有當(dāng)IO操作完成之后,用戶進(jìn)程才能運(yùn)行。JAVA傳統(tǒng)的BIO屬于此種方式。(jdk1.4以前)

同步非阻塞IO

JAVA NIO(jdk1.4以后引入)

在此種方式下,用戶進(jìn)程發(fā)起一個(gè)IO操作以后邊可返回做其它事情,但是用戶進(jìn)程需要時(shí)不時(shí)的詢問IO操作是否就緒,這就要求用戶進(jìn)程不停的去詢問,從而引入不必要的CPU資源浪費(fèi)。JAVA的NIO就屬于同步非阻塞IO

多路復(fù)用IO

redis、nginx、netty;reactor模式

select,epoll;有時(shí)也稱這種IO方式為事件驅(qū)動(dòng)IO。

select/epoll的好處就在于單個(gè)process就可以同時(shí)處理多個(gè)網(wǎng)絡(luò)連接的IO。它的基本原理就是select/epoll這個(gè)函數(shù)會(huì)不斷的輪詢所負(fù)責(zé)的所有socket,當(dāng)某個(gè)socket有數(shù)據(jù)到達(dá)了,就通知用戶進(jìn)程.

多路復(fù)用中,通過select函數(shù),可以同時(shí)監(jiān)聽多個(gè)IO請(qǐng)求的內(nèi)核操作,只要有任意一個(gè)IO的內(nèi)核操作就緒,都可以通知select函數(shù)返回,再進(jìn)行系統(tǒng)調(diào)用recvfrom()完成IO操作。

這個(gè)過程應(yīng)用程序就可以同時(shí)監(jiān)聽多個(gè)IO請(qǐng)求,這比起基于多線程阻塞式IO要先進(jìn)得多,因?yàn)榉?wù)器只需要少數(shù)線程就可以進(jìn)行大量的客戶端通信。

信號(hào)驅(qū)動(dòng)式IO模型

在unix系統(tǒng)中,應(yīng)用程序發(fā)起IO請(qǐng)求時(shí),可以給IO請(qǐng)求注冊(cè)一個(gè)信號(hào)函數(shù),請(qǐng)求立即返回,操作系統(tǒng)底層則處于等待狀態(tài)(等待數(shù)據(jù)就緒),直到數(shù)據(jù)就緒,然后通過信號(hào)通知主調(diào)程序,主調(diào)程序才去調(diào)用系統(tǒng)函數(shù)recvfrom()完成IO操作。

信號(hào)驅(qū)動(dòng)也是一種非阻塞式的IO模型,比起上面的非阻塞式IO模型,信號(hào)驅(qū)動(dòng)式IO模型不需要輪詢檢查底層IO數(shù)據(jù)是否就緒,而是被動(dòng)接收信號(hào),然后再調(diào)用recvfrom執(zhí)行IO操作。

比起多路復(fù)用IO模型來說,信號(hào)驅(qū)動(dòng)IO模型針對(duì)的是一個(gè)IO的完成過程, 而多路復(fù)用IO模型針對(duì)的是多個(gè)IO同時(shí)進(jìn)行時(shí)候的場(chǎng)景。

異步IO

在此種模式下,整個(gè)IO操作(包括等待數(shù)據(jù)就緒,復(fù)制數(shù)據(jù)到應(yīng)用程序工作空間)全都交給操作系統(tǒng)完成。數(shù)據(jù)就緒后操作系統(tǒng)將數(shù)據(jù)拷貝進(jìn)應(yīng)用程序運(yùn)行空間之后,操作系統(tǒng)再通知應(yīng)用程序,這個(gè)過程中應(yīng)用程序不需要阻塞

區(qū)別

如果你在燒水:

同步阻塞:你將水放在爐子上,然后在那兒等著,還要一直觀察:水燒開了沒啊!

同步非阻塞:你將水放在爐子上,就去看電視了了。每過一會(huì),就到爐子邊觀察:水燒開了沒啊!

多路復(fù)用:有人改進(jìn)了燒水壺,水開了之后會(huì)自動(dòng)發(fā)出哨聲,你只需要安心看電視等待哨響通知你水燒開了。

異步非阻塞:你安排其他人燒水,水燒開后放在特地場(chǎng)合,會(huì)打電話通知你,安心看電視等待就可以了。

阻塞、非阻塞、多路IO復(fù)用,都是同步IO,異步必定是非阻塞的,所以不存在異步阻塞和異步非阻塞的說法。真正的異步IO需要CPU的深度參與。換句話說,只有用戶線程在操作IO的時(shí)候根本不去考慮IO的執(zhí)行,全部都交給CPU去完成,而只需要等待一個(gè)完成信號(hào)的時(shí)候,才是真正的異步IO。所以,fork子線程去輪詢、死循環(huán)或者使用select、poll、epoll,都不是異步

比較經(jīng)典的一個(gè)舉例

阻塞I/O模型

老李去火車站買票,排隊(duì)三天買到一張退票。耗費(fèi):在車站吃喝拉撒睡 3天,其他事一件沒干。

非阻塞I/O模型

老李去火車站買票,隔12小時(shí)去火車站問有沒有退票,三天后買到一張票。耗費(fèi):往返車站6次,路上6小時(shí),其他時(shí)間做了好多事。

I/O復(fù)用模型

1.select/poll 老李、老王、老劉…一行人去火車站買票,一起委托給黃牛(select黃牛最大只能接1024個(gè)人的訂單/pool黃牛不限制),select/pool黃牛一直等待出票結(jié)果,待黃牛取到票后,不知道這張票是屬于誰的(需要根據(jù)票面逐一詢問),確認(rèn)后通知相應(yīng)人去火車站交錢領(lǐng)票。

2.epoll 老李、老王、老劉…一行人(無人員個(gè)數(shù)限制)去火車站買票,一起委托給黃牛,黃牛買到后不需要確認(rèn)就可以知道這張票的委托人是誰,然后通知其去火車站交錢領(lǐng)票。

多路復(fù)用的意思是:黃牛在承接老李的訂單之后,同時(shí)也接了老王、老劉的購(gòu)票訂單;大家使用同一個(gè)黃牛

信號(hào)驅(qū)動(dòng)I/O模型

老李去火車站買票,給售票員留下電話,有票后,售票員電話通知老李,然后老李去火車站交錢領(lǐng)票。耗費(fèi):往返車站2次,路上2小時(shí),免黃牛費(fèi)100元,無需打電話,也不需要黃牛

異步I/O模型

老李去火車站買票,給售票員留下電話,有票后,售票員快遞送票上門后電話通知其收貨。耗費(fèi):往返車站1次,路上1小時(shí),免黃牛費(fèi)100元,無需打電話,也不需要黃牛

再談IO多路復(fù)用

I/O多路復(fù)用就通過一種機(jī)制,可以監(jiān)視多個(gè)描述符,一旦某個(gè)描述符就緒(一般是讀就緒或者寫就緒),能夠通知程序進(jìn)行相應(yīng)的讀寫操作。但select,poll,epoll本質(zhì)上都是同步I/O,因?yàn)樗麄兌夹枰谧x寫事件就緒后自己負(fù)責(zé)進(jìn)行讀寫,也就是說這個(gè)讀寫過程是阻塞的,而異步I/O則無需自己負(fù)責(zé)進(jìn)行讀寫,異步I/O的實(shí)現(xiàn)會(huì)負(fù)責(zé)把數(shù)據(jù)從內(nèi)核拷貝到用戶空間。

多路復(fù)用如下面所示:指的其實(shí)是在單個(gè)線程通過記錄跟蹤每一個(gè)Sock(I/O流)的狀態(tài)來同時(shí)管理多個(gè)I/O流

個(gè)人的一些理解:

如上圖做一個(gè)簡(jiǎn)單的比喻:左邊有若干取水器,需要到右邊水龍頭進(jìn)行取水操作,每個(gè)取水器和水龍頭是一一對(duì)應(yīng)的關(guān)系,但是中間段是斷開的,需要將水管連接上(一個(gè)水管相當(dāng)于一個(gè)IO線程),才可以進(jìn)行取水操作了(注意水龍頭不是一直都有水流的,只有當(dāng)取水器連接上才會(huì)觸發(fā)輸水操作)。下面依次對(duì)不同的IO模型進(jìn)行講解:

1、傳統(tǒng)阻塞BIO:每個(gè)取水器和水龍頭之間都需要一個(gè)連接水管,水管連接上觸發(fā)取水操作,水龍頭才會(huì)輸水。這樣有幾個(gè)取水器就需要幾個(gè)水管,另外水管接上之后并不會(huì)馬上就能取到水,之間一直處于阻塞狀態(tài),當(dāng)取水器過多時(shí)沒有足夠的水管來進(jìn)行連接

線程池模式:水池中存在10根水管,每當(dāng)取水器有取水請(qǐng)求時(shí),就去水池中拿一根水管使用,水管會(huì)根據(jù)取水器編號(hào)接到相應(yīng)的水龍頭上。當(dāng)取水器請(qǐng)求過多時(shí),需要不停的進(jìn)行水管切換。

2、多路復(fù)用IO:

select/poll:全部的取水器均復(fù)用一根水管,沒有多余的水管可用,所有的取水器均接到這一根水管上。(區(qū)別是select模式僅支持1024個(gè)取水器的接入,而poll不限制取水器個(gè)數(shù))。當(dāng)水龍頭有水流過來時(shí),水管會(huì)提前收到通知,但不知道是哪個(gè)水龍頭。則此時(shí)水管需要每個(gè)水龍頭都接上試一下,當(dāng)發(fā)現(xiàn)其中一個(gè)水龍頭有水流時(shí)則將其運(yùn)到與其相連的取水器中。

epoll部的取水器均復(fù)用一根水管,沒有多余的水管可用,所有的取水器均接到這一根水管上。(與select/poll區(qū)別是:當(dāng)水龍頭有水流過來時(shí),水管就已經(jīng)知道是哪根水龍頭在運(yùn)水了,直接將水管接上相應(yīng)的水龍頭即可)。

偽代碼描述各IO區(qū)別

非阻塞忙輪詢式

  1. while true 
  2.   for i in fd[] 
  3.   { 
  4.       if i has data 
  5.       read until unavailable 
  6.   } 

把所有流從頭到尾查詢一遍,就可以處理多個(gè)流了,但這樣做很不好,因?yàn)槿绻械牧鞫紱]有I/O事件,白白浪費(fèi)CPU時(shí)間片

select:服務(wù)端一直在輪詢、監(jiān)聽如果有客戶端鏈接上來就創(chuàng)建一個(gè)連接放到數(shù)組A中,繼續(xù)輪詢這個(gè)數(shù)組,如果在輪詢的過程中有客戶端發(fā)生IO事件就去處理;select只能監(jiān)視1024個(gè)連接(一個(gè)進(jìn)程只能創(chuàng)建1024個(gè)文件);而且存在線程安全問題;

  1. while true 
  2.   select(fds[]) //阻塞這里,直到有一個(gè)流有I/O事件時(shí),才往下執(zhí)行,數(shù)組的大小只有1024 
  3.   for i in fds[] 
  4.   { 
  5.       if i has data 
  6.       read until unavailable 
  7.   } 

它僅僅知道了,有I/O事件發(fā)生了,卻并不知道是哪那幾個(gè)流(可能有一個(gè),多個(gè),甚至全部),我們只能無差別輪詢所有流,找出能讀出數(shù)據(jù),或者寫入數(shù)據(jù)的流,對(duì)他們進(jìn)行操作。所以select具有O(n)的無差別輪詢復(fù)雜度,同時(shí)處理的流越多,無差別輪詢時(shí)間就越長(zhǎng)

  • poll:在select做了許多修復(fù),比如不限制監(jiān)測(cè)的連接數(shù);但是也有線程安全問題;

poll本質(zhì)上和select沒有區(qū)別,它將用戶傳入的數(shù)組拷貝到內(nèi)核空間,然后查詢每個(gè)fd對(duì)應(yīng)的設(shè)備狀態(tài), 但是它沒有最大連接數(shù)的限制,原因是它是基于鏈表來存儲(chǔ)的.

  • epoll:也是監(jiān)測(cè)IO事件,但是如果發(fā)生IO事件,它會(huì)告訴你是哪個(gè)連接發(fā)生了事件,就不用再輪詢?cè)L問。而且它是線程安全的,但是只有l(wèi)inux平臺(tái)支持;
  1. while true 
  2.   active_fds[] = epoll_wait(epollfd) 
  3.   for i in active_fds[] 
  4.   { 
  5.       read or write till 
  6.   } 

epoll可以理解為event poll,不同于忙輪詢和無差別輪詢,epoll會(huì)把哪個(gè)流發(fā)生了怎樣的I/O事件通知我們。所以我們說epoll實(shí)際上是事件驅(qū)動(dòng)(每個(gè)事件關(guān)聯(lián)上fd)的,此時(shí)我們對(duì)這些流的操作都是有意義的。(復(fù)雜度降低到了O(1))

 

責(zé)任編輯:武曉燕 來源: 你呀不牛
相關(guān)推薦

2022-02-14 07:03:31

網(wǎng)站安全MFA

2022-06-26 09:40:55

Django框架服務(wù)

2021-07-31 11:40:55

Openresty開源

2023-08-02 08:35:54

文件操作數(shù)據(jù)源

2022-08-01 07:57:03

數(shù)組操作內(nèi)存

2021-11-04 06:58:31

CSS性能設(shè)備

2022-08-30 13:48:16

LinuxMySQL內(nèi)存

2021-11-09 23:54:19

開發(fā)SMI Linkerd

2022-12-05 09:10:21

2021-10-26 09:55:52

CAP理論分布式

2022-03-15 20:18:35

單元測(cè)試工具

2021-12-29 08:27:05

ByteBuffer磁盤服務(wù)器

2022-03-08 17:52:58

TCP格式IP

2022-03-31 18:59:43

數(shù)據(jù)庫(kù)InnoDBMySQL

2016-09-06 10:39:30

Dell Techno

2022-02-14 10:16:22

Axios接口HTTP

2021-07-15 07:23:28

Singlefligh設(shè)計(jì)

2021-11-26 07:00:05

反轉(zhuǎn)整數(shù)數(shù)字

2023-08-14 08:38:26

反射reflect結(jié)構(gòu)體

2023-04-26 00:19:18

AICSI-RSChatGPT
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)