一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

IO如何實現(xiàn)

科技綠洲 ? 來源:了不起 ? 作者:了不起 ? 2023-09-25 10:57 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

IO模型

我們的程序基本上都是對數(shù)據(jù)的IO操作以及基于CPU的運算。

基于Java的開發(fā)大部分是網(wǎng)絡(luò)相關(guān)的編程,不管是基于如Tomcat般的Web容器,或是基于Netty開發(fā)的應(yīng)用間的RPC服務(wù)。為了提供系統(tǒng)吞吐量, 降低硬件資源的開銷,IO模型也在不斷適應(yīng)大規(guī)模、高并發(fā)需求不斷演進,今天我們就來看看這個在網(wǎng)絡(luò)上高頻出現(xiàn)的詞匯IO模型

linux IO模型

首先我們要明確,用戶程序從計算機硬件讀取數(shù)據(jù)(包括文件、網(wǎng)絡(luò)數(shù)據(jù)等),會經(jīng)歷數(shù)據(jù)從硬件設(shè)備中讀取到系統(tǒng)內(nèi)核后,再拷貝到用戶空間的過程。在linux系統(tǒng)中,針對這一操作提供了5種IO模型用于優(yōu)化不同場景下的IO操作。

  • 同步阻塞IO 系統(tǒng)程序調(diào)用recvfrom阻塞等待內(nèi)核將數(shù)據(jù)準備(從網(wǎng)卡將數(shù)據(jù)讀取到內(nèi)存中)。之后用戶通過recvfrom等待內(nèi)核將數(shù)據(jù)準備好,此時內(nèi)核將數(shù)據(jù)從內(nèi)核緩沖區(qū)復(fù)制到用戶態(tài)緩沖區(qū)。

圖片

blocking I/O發(fā)起system call recvfrom()時,進程將一直阻塞等待另一端Socket的數(shù)據(jù)到來。在該模式下,會阻塞其他連接的建立,因此一般都會通過多線程處理Socket數(shù)據(jù)的讀取。

Blocking I/O優(yōu)點是簡單易用,對于本地I/O而言性能很高。缺點是處理網(wǎng)絡(luò)I/O時,造成進程阻塞,以及創(chuàng)建線程的資源消耗。

  • 同步非阻塞IO
    系統(tǒng)程序調(diào)用recvfrom時并不會阻塞等待,但是需要調(diào)用方不停的去輪詢內(nèi)核,獲取數(shù)據(jù)準備狀態(tài)。之后用戶發(fā)起的(同步)recvfrom檢查到內(nèi)核將數(shù)據(jù)準備好后,進行數(shù)據(jù)由內(nèi)核到用戶空間的復(fù)制。

圖片

相對于阻塞I/O的等待,非阻塞I/O隔一段時間就就需要發(fā)起system call判斷數(shù)據(jù)是否就緒。如果數(shù)據(jù)就緒,就從kernel space復(fù)制到user space,操作數(shù)據(jù); 否則,kernel會立即返回EWOULDBLOCK這個錯誤。

recvfrom有個參數(shù)叫flags,默認情況下阻塞。可以設(shè)置flag為非阻塞讓kernel在數(shù)據(jù)未就緒時直接返回。這就是”非阻塞”主要是指數(shù)據(jù)準備階段。

  • IO多路復(fù)用
    系統(tǒng)程序調(diào)用select/poll/epoll會阻塞等待至少有一個套接字就緒則返回。用戶(同步)調(diào)用recvfrom,獲取這些就緒的套接字,輪詢將數(shù)據(jù)由內(nèi)核復(fù)制到用戶態(tài)緩沖區(qū)。

圖片

I/O Multiplexing首先向kernel發(fā)起system call,傳入file descriptor和感興趣的事件(readable、writable等)讓kernel監(jiān)測, 當(dāng)其中一個或多個fd數(shù)據(jù)就緒,就會返回結(jié)果。程序再發(fā)起真正的I/O操作recvfrom讀取數(shù)據(jù)。

  • 信號驅(qū)動IO
    系統(tǒng)調(diào)用sigaction不會阻塞。當(dāng)數(shù)據(jù)準備完成之后,會主動的通知用戶進程數(shù)據(jù)已經(jīng)準備完成,對用戶進程做一個回調(diào)。用戶發(fā)起的(同步)recvfrom將就緒的數(shù)據(jù)由內(nèi)核復(fù)制到用戶態(tài)緩沖區(qū)。

圖片

第一次發(fā)起system call不會阻塞進程,kernel的數(shù)據(jù)就緒后會發(fā)送一個signal給進程。進而發(fā)起真正的IO操作。

  • 異步IO
    系統(tǒng)調(diào)用aio_read不會阻塞。直到I/O數(shù)據(jù)準備好內(nèi)核會直接將數(shù)據(jù)復(fù)制到用戶空間,然后內(nèi)核主動會給用戶進程發(fā)送通知,告訴用戶進程信號表示并進行數(shù)據(jù)處理。

圖片

既然說到異步IO,則前面的幾種IO模型都是同步的,由上圖可以看到,在數(shù)據(jù)拷貝(內(nèi)核態(tài)到用戶態(tài))時,仍然是阻塞的。在異步IO中,請求連接到內(nèi)核后,從數(shù)據(jù)準備到復(fù)制整個過程 都是在內(nèi)核中完成,對應(yīng)用戶程序不會阻塞,直到請求數(shù)據(jù)完全準備好后,通過回調(diào)函數(shù)通知用戶程序完成整個IO操作。

Java中的IO模型

Java中提供的IO相關(guān)的API,主要是基于操作系統(tǒng)底層的IO的操作。在Java中的BIO、NIO、AIO屬于Java對操作系統(tǒng)的各種IO模型的封裝。當(dāng)我們使用這些API時,不用關(guān)注底層IO的實現(xiàn)。

  • BIO

同步阻塞IO ,服務(wù)端通過阻塞輸入流來監(jiān)聽客戶端是否有數(shù)據(jù)寫入,當(dāng)處理輸入數(shù)據(jù)時,程序會等待內(nèi)核完成處理完成并返回后才會繼續(xù)執(zhí)行。

圖片

上圖可以看到,服務(wù)端通過ServerSocket#accept阻塞方法監(jiān)聽客戶端的接入,然后阻塞在通過阻塞輸入流等待客戶端的輸入,如果一直沒有輸入,則其他客戶端都會被阻塞在此。

圖片

我們可以通過多線程來改善,每個客戶端連接時,都由獨立的線程來處理,雖然通過多線程可以解決客戶端間的阻塞問題,但單個線程內(nèi)然是阻塞模式, 并且當(dāng)客戶端過多時需要足夠的線程來支持,比較耗費系統(tǒng)資源。

圖片

  • NIO

同步非阻塞IO ,基于多路復(fù)用模型,依賴于服務(wù)器操作系統(tǒng),通過一個Selector即可監(jiān)聽多個連接,并進行IO處理。但要注意,如果處理IO的過程較長一樣會影響到其他的連接。

圖片

服務(wù)端通過Selector#select阻塞方法,監(jiān)聽Channel狀態(tài),一旦有Channel準備就緒,程序才會繼續(xù)往下執(zhí)行,因此需要不斷輪詢并監(jiān)控Channel的狀態(tài)變更。與BIO的多線程模式非常相似,只不過BIO是基于多線程技術(shù)實現(xiàn),而NIO是基于操作系統(tǒng)底層提供的函數(shù),效率更好且資源消耗更少。

圖片

  • AIO

異步非阻塞IO ,在JDK1.7之后提供了異步的相關(guān)Channel,AIO提供異步功能, 基于回調(diào)函數(shù)實現(xiàn) ,同樣依賴于操作系統(tǒng)底層的異步IO模型,異步操作的實現(xiàn)是在對應(yīng)的 accept、connection、read、write等方法異步執(zhí)行,完成后會主動調(diào)用回調(diào)函數(shù)。

圖片

其中accept、read等方法都是非阻塞的,即立即返回結(jié)果,幾乎所有的異步操作都是基于回調(diào)函數(shù)實現(xiàn),這種方式不管是對操作系統(tǒng)資源的利用以及效率上都是最佳的實現(xiàn)。

圖片

雖然三種IO模型的演進是為了提升系統(tǒng)處理IO的能力,但是開發(fā)的復(fù)雜度也同步上升:

  • BIO方式適用于連接數(shù)目比較小且固定的架構(gòu),需要依賴于線程來支持多個客戶端接入,但程序直觀簡單易理解。
  • NIO方式適用于連接數(shù)目多且連接比較短(輕操作)的架構(gòu),比如聊天服務(wù)器,并發(fā)局限于應(yīng)用中,編程比較復(fù)雜。
  • AIO方式使用于連接數(shù)目多且連接比較長(重操作)的架構(gòu),比如相冊服務(wù)器,充分調(diào)用OS參與并發(fā)操作,編程比較復(fù)雜。

同/異步與(非)阻塞

關(guān)于阻塞、非阻塞、同步、異步這些名詞的解釋,可以在網(wǎng)上找到很多解釋,但是如何能夠從本質(zhì)上描述其含義,正如IO與NIO中說到的阻塞與非阻塞,又是怎么體現(xiàn)的呢?

我們一般說說的IO模型,其實是服務(wù)端進行IO操作執(zhí)行與實現(xiàn)的形式,程序?qū)?shù)據(jù)從程序?qū)懭牖蜃x寫時,與硬件設(shè)備(比如硬盤、網(wǎng)卡)間,基于操作系統(tǒng)提供的系統(tǒng)api實現(xiàn)數(shù)據(jù)由用戶態(tài)與內(nèi)核態(tài)交互的一種形式。

  • 同步
    程序執(zhí)行需要等待返回后才會繼續(xù)。
  • 異步
    與同步相反,比較直觀的就是線程。
  • 阻塞IO
    程序需要等待內(nèi)核IO操作完成后返回到用戶空間繼續(xù)執(zhí)行用戶程序的操作指令。這里的阻塞主要是調(diào)用操作系統(tǒng)api被阻塞導(dǎo)致程序掛起,描述的是程序當(dāng)前執(zhí)行的狀態(tài)。
  • 非阻塞IO
    既然阻塞是調(diào)用操作系統(tǒng)api被阻塞,那么非阻塞則相反,得益于操作系統(tǒng)提供的函數(shù)支持,一般是通過輪詢機制與回調(diào)函數(shù)實現(xiàn)。

同步與異步屬于程序發(fā)起請求的方式;阻塞與非阻塞屬于服務(wù)響應(yīng)IO操作的底層實現(xiàn)方式。

示例

基于上面的理解,我們看下在Java中如何實現(xiàn)BIO、NIO以及AIO。

BIO

Server:

serverSocket = new ServerSocket(port);
  // 阻塞直到有連接
  Socket clientSocket = serverSocket.accept();
  // 阻塞讀取數(shù)據(jù)
  BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  log.info(" >> >> > Server接收消息:{}" , reader.readLine());
  socket.shutdownInput();
  
  log.info(" >> >> > Server回復(fù)消息:{}" , message);
  PrintWriter writer = new PrintWriter(socket.getOutputStream());
  writer.println(message);

Client:

// 連接服務(wù)端
  socket = new Socket("127.0.0.1",port);
  OutputStream out = socket.getOutputStream();
  out.write(message.getBytes());
  socket.shutdownOutput();
  
  BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
  log.info("接收Server回復(fù):{}", reader.readLine());

NIO

省略

AIO

Server:

//
    serverSocketChannel = AsynchronousServerSocketChannel.open();
    //綁定端口
    serverSocketChannel.bind(new InetSocketAddress(port));
    //異步接收客戶端連接
    serverSocketChannel.accept(null, new AcceptCompletionHandler< String >());

    /**
     * 處理客戶端連接
     * @param < T >
     */
    public class AcceptCompletionHandler< T > implements CompletionHandler< AsynchronousSocketChannel,T > {

        @Override
        public void completed(AsynchronousSocketChannel result, T attachment) {
            log.info(" >> > 客戶端接入...");
            ByteBuffer byteBuffer = ByteBuffer.allocate(512);
            //異步讀客戶端數(shù)據(jù)
            result.read(byteBuffer, byteBuffer, new ReadCompletionHandler());
            //接收其他的客戶端連接的
            serverSocketChannel.accept(null, this);
        }

        @Override
        public void failed(Throwable exc, T attachment) {
            log.error(" >> > 客戶端接入失敗:{}", exc.getMessage());
        }
    }

    /**
     * 處理ServerChannel讀取
     * @param < T >
     */
    public class ReadCompletionHandler< T extends Buffer > implements CompletionHandler< Integer, T >{

        @Override
        public void completed(Integer result, T attachment) {
            if(attachment.hasRemaining()){
                // 切換成讀模式
                attachment.flip();
                //
                if( attachment instanceof ByteBuffer ){
                    byte[] bytes = new byte[attachment.remaining()];
                    ((ByteBuffer)attachment).get(bytes); // 從Buffer中取數(shù)據(jù) get
                    log.info("Server接收消息:{}", new String(bytes));
                }
            }
        }

        @Override
        public void failed(Throwable exc, T attachment) {
            log.error("Server接收消息失?。簕}", exc.getMessage());
        }
    }

Client:

//創(chuàng)建異步通道實例
    socketChannel = AsynchronousSocketChannel.open();
    //連接服務(wù)端,異步方式
    socketChannel.connect(new InetSocketAddress("127.0.0.1",port), null, new ConnetionComplateHandler());
    // 消息發(fā)送
    this.socketChannel.write(Charset.defaultCharset().encode(message));
    /**
     *
     * @param < T >
     */
    public class ConnetionComplateHandler< T > implements CompletionHandler< Void, T > {

        @Override
        public void completed(Void result, T attachment) {
            log.info("Client連接服務(wù)的成功...");
        }

        @Override
        public void failed(Throwable exc, T attachment) {

        }
    }

結(jié)束語

通過了解操作系統(tǒng)層面的IO模型可以讓我們理解IO是如何實現(xiàn),以及通過Java語言提供的類庫實現(xiàn)了操作系統(tǒng)底層API調(diào)用的復(fù)雜性。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • IO
    IO
    +關(guān)注

    關(guān)注

    0

    文章

    491

    瀏覽量

    40583
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    7256

    瀏覽量

    91933
  • Linux系統(tǒng)
    +關(guān)注

    關(guān)注

    4

    文章

    605

    瀏覽量

    28636
  • 程序
    +關(guān)注

    關(guān)注

    117

    文章

    3826

    瀏覽量

    83021
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    51單片機總線擴IO如何實現(xiàn)?

    51單片機工作在總線方式,準備用1個8位鎖存器擴充8個輸出口,要求上電時,輸出口必須保證為高電平,系統(tǒng)復(fù)位時(如按下復(fù)位鍵不放),也要確保輸出口為高電平,電路如何實現(xiàn),問題的關(guān)鍵是上電狀態(tài)如何為高。
    發(fā)表于 09-30 02:24

    怎么用8個IO實現(xiàn)8個波形?

    要用8個IO實現(xiàn)8個波形,8路信號同時進行的,具體波形見附件中的文件,跪求大神指導(dǎo)指導(dǎo),給個思路,謝謝。OSC.zip (62.49 KB )
    發(fā)表于 03-08 20:16

    ds1302時鐘芯片dat由低位到高位寫入io怎么實現(xiàn)?

    命令dat由低位到高位寫入io中,也就是是命令寫入函數(shù) 。 正確的理解是例如 dat=0x45即dat=0100 0101和0x01進行‘’“&”運算, i=0時,屏蔽掉前七位 即0100
    發(fā)表于 04-30 01:35

    Xilinx7系列IO實現(xiàn)差分信號

    都可配置成輸入、輸出。每個bank的首尾管腳只能作為單端I/O,其余48個I/O則可配置成24對差分I/O。在差分信號的實現(xiàn)過程中,管腳分配應(yīng)選擇相應(yīng)電平標(biāo)準的bank中除首尾以外的其他48個IO
    發(fā)表于 12-23 17:17

    基于ARM的地鐵用安全型智能IO的設(shè)計與實現(xiàn)

    地鐵信號設(shè)備中輸入輸出設(shè)備是信號邏輯和現(xiàn)場設(shè)備之間的接口,有著四高(高安全,高可靠,高可維護,高可用)要求,目前信號系統(tǒng)廠家的傳統(tǒng)做法是整個信號系統(tǒng)產(chǎn)品由一家
    發(fā)表于 10-27 15:48 ?12次下載

    基于PROFINET IO實現(xiàn)S7-1200與S120通訊

    S7-1200 與SINAMICS S120 之間通過PROFINET IO 可進行周期性或: 非周期性數(shù)據(jù)通訊,使用功能塊DPWR_DAT/DPRD_DAT,S7-1200 通過PROFINET
    發(fā)表于 09-29 16:50 ?30次下載
    基于PROFINET <b class='flag-5'>IO</b><b class='flag-5'>實現(xiàn)</b>S7-1200與S120通訊

    利用到電容充放電原理實現(xiàn)一條IO實現(xiàn)兩個按鍵

    .MCU_IO1設(shè)定為輸入,如果J1、J2均不按下,此時MCU_IO1可以理解成一個阻值很大的電阻接地,電容C1上的電荷會通過這個電阻逐漸釋放掉,這樣C1上的電壓會逐漸降低到零。因為C1上的電壓
    的頭像 發(fā)表于 03-26 08:39 ?9278次閱讀
    利用到電容充放電原理<b class='flag-5'>實現(xiàn)</b>一條<b class='flag-5'>IO</b><b class='flag-5'>實現(xiàn)</b>兩個按鍵

    單片機應(yīng)用系統(tǒng)中如何通過IO實現(xiàn)斷電自關(guān)機?通過電路圖給你講解

    單片機應(yīng)用系統(tǒng)中,常有用單片機的IO口來實現(xiàn)自關(guān)機(徹底關(guān)機)的功能。一般用單片機的一個IO口控制一個電子開關(guān)來實現(xiàn),因單片機關(guān)電后,失去電源,所以在關(guān)機時,
    的頭像 發(fā)表于 09-24 11:45 ?7473次閱讀
    單片機應(yīng)用系統(tǒng)中如何通過<b class='flag-5'>IO</b><b class='flag-5'>實現(xiàn)</b>斷電自關(guān)機?通過電路圖給你講解

    MAXREFDES150 Pocket IO如何提高PLC平臺效率

    了解MAXREFDES150 Pocket IO?如何實現(xiàn)比之前的PLC平臺效率提高30%,體積減小2?倍。Pocket IO是完備的工業(yè)平臺,配備有30路IO,具有三種不同的傳感器輸
    的頭像 發(fā)表于 10-11 03:07 ?3597次閱讀

    使用Google Assistant和Adafruit IO實現(xiàn)家庭自動化

    電子發(fā)燒友網(wǎng)站提供《使用Google Assistant和Adafruit IO實現(xiàn)家庭自動化.zip》資料免費下載
    發(fā)表于 12-05 09:57 ?0次下載
    使用Google Assistant和Adafruit <b class='flag-5'>IO</b><b class='flag-5'>實現(xiàn)</b>家庭自動化

    FPGA數(shù)字IO如何實現(xiàn)DAC功能

    假設(shè)方波頻率為f0。橫軸諧波次數(shù)為0的柱狀圖代表直流分量的幅值,也就是方波的平均電壓(與占空比有關(guān)),諧波次數(shù)為1代表頻率為f0的正弦波分量的幅值,3代表,3*f0的正弦波分量幅值,以此類推。
    的頭像 發(fā)表于 12-07 10:31 ?1940次閱讀

    求一種Ti60F100高速IO實現(xiàn)HDMI環(huán)出方案

    xilinx和altera都有通過IO驅(qū)動HDMI的方案,支持的分辨率各有不同,這跟不同系列的FPGA性能是相關(guān)的。
    的頭像 發(fā)表于 03-09 14:20 ?3255次閱讀
    求一種Ti60F100高速<b class='flag-5'>IO</b><b class='flag-5'>實現(xiàn)</b>HDMI環(huán)出方案

    請問FPGA數(shù)字IO如何實現(xiàn)DAC功能呢?

    假設(shè)方波頻率為f0。橫軸諧波次數(shù)為0的柱狀圖代表直流分量的幅值,也就是方波的平均電壓(與占空比有關(guān)),諧波次數(shù)為1代表頻率為f0的正弦波分量的幅值,3代表,3*f0的正弦波分量幅值,以此類推。
    發(fā)表于 06-28 14:50 ?712次閱讀
    請問FPGA數(shù)字<b class='flag-5'>IO</b>如何<b class='flag-5'>實現(xiàn)</b>DAC功能呢?

    氣壓調(diào)節(jié)遠程IO實現(xiàn)制冷空調(diào)智能控制的重要技術(shù)

    應(yīng)用介紹 本項目為大型制冷系統(tǒng)的氣壓調(diào)節(jié)項目,本次應(yīng)用工位為項目配套電氣控制柜??蛻羰褂梦鏖T子PLC,原IO系統(tǒng)使用西門子遠程IO:ET200SP系列,本項目因受到西門子貨期影響的機會,使我們得到
    的頭像 發(fā)表于 10-31 11:40 ?750次閱讀
    氣壓調(diào)節(jié)遠程<b class='flag-5'>IO</b>:<b class='flag-5'>實現(xiàn)</b>制冷空調(diào)智能控制的重要技術(shù)

    遠程IO實現(xiàn)設(shè)備間高效通信與控制的橋梁

    在當(dāng)今數(shù)字化時代,遠程IO(輸入/輸出)技術(shù)已成為實現(xiàn)工業(yè)自動化、智慧城市等系統(tǒng)中不可或缺的一部分。那么,遠程IO究竟是什么?它又是如何工作的呢?今天,我將帶您探索遠程IO技術(shù)的奧秘。
    的頭像 發(fā)表于 09-06 17:22 ?941次閱讀
    遠程<b class='flag-5'>IO</b>:<b class='flag-5'>實現(xiàn)</b>設(shè)備間高效通信與控制的橋梁