認識網路IO模型

来源:https://www.cnblogs.com/CoderGan/archive/2022/07/18/16488894.html
-Advertisement-
Play Games

硬體準備: CH32V103 開發板/核心版, WCH-Link. 軟體準備: 軟體主要是用於編譯的 RISC-V GCC , 和用於燒錄的 OpenOCD., RISC-V GCC 可以選擇公版或者WCH版, OpenOCD 暫時只能用WCH定製版本, 用公版的無法識別 wlink ...


  • BIO模型

    在Linux中,預設情況下所有socket都是阻塞模式。用戶線程調用系統函數read()【system call】,內核開始準備數據(從磁碟/網路獲取數據),內核准備數據完成後,用戶線程完成數據從內核拷貝到用戶空間的應用程式緩衝區,數據拷貝完成後,請求才返回。從發起read請求到完成內核到應用程式的拷貝,整個過程都是阻塞的。

    為了減輕線程阻塞的弊端,實際上,每個Read/Write請求都會分配單獨線程進行單獨處理。在低併發時期,這種每個請求每線程的處理方式是可以應付的,但是如果在高併發期間(如:業務高峰期),就會分配大量的線程完成請求處理。因此會帶來非常大的性能損耗。
  • NIO模型

    用戶線程在發起Read請求後立即返回,不用等待內核准備數據的過程。如果Read請求沒讀取到數據,用戶線程會不斷輪詢發起Read請求,直到數據到達(內核准備好數據)後才停止輪詢。
    非阻塞IO模型雖然避免了由於線程阻塞問題帶來的大量線程消耗,但是頻繁的重覆輪詢大大增加了請求次數,對CPU消耗也比較明顯。
  • 多路復用模型

    多路復用IO模型,建立在多路事件分離函數select,poll,epoll之上。在發起read請求前,先更新select的socket監控列表,然後等待select(或poll或epoll)函數返回(此過程是阻塞的)。當某個socket有數據到達時,select函數返回。此時用戶線程才正式發起read或write請求,處理數據。這種模式用一個專門的監視線程去檢查多個socket,如果某個socket有數據到達就交給工作線程處理。由於等待Socket數據到達過程非常耗時,所以這種方式解決了阻塞IO模型一個Socket連接就需要一個線程的問題,也不存在非阻塞IO模型忙輪詢帶來的CPU性能損耗的問題。

    多路復用的本質,在我看來其實就是通過儘可能少(預期一次)的系統調用(system call),就可以拿到所有socket的狀態(是否可讀),然後程式只需要對那些返回狀態為可讀或可寫的socket進行處理。

     1 // NIO核心代碼
     2 // 初始化
     3 channel = ServerSocketChannel.open();
     4 channel.bind(port);
     5 channel.configureBlocking(false);
     6 // selector 註冊accept事件
     7 selector = Selector.open(); 
     8 channel.register(selector, SelectionKey.OP_ACCEPT);
     9 while(true){
    10     while(selector.select(timeout)>0){ // 有新的事件
    11         // 獲取到可處理的 Socket
    12         Set<SelectionKey> keySet = selector.selectedKeys();
    13         Iterator<SelectionKey> iter = keySet.iterator();
    14         while (iter.hasNext()) {    // 迴圈處理,處理之後應該從迭代器中移除
    15             SelectionKey key = iter.next();
    16             iter.remove();
    17             if (key.isAcceptable()) {    // 新連接 acceptHandle(key); }
    18             else if (key.isReadable()) {  // 讀事件 readHandle(key);  }
    19             else if (key.isWritable()) {  // 寫事件 writeHandle(key);  }
    20     }
    21 }
    22 }
    View Code

    實際上,linux的多路復用有三種實現方式,select和poll以及epoll,它們之間的關係是進化關係,性能都是遞進的。

    • select

      select 是操作系統提供的系統調用函數,通過它,我們可以把一個文件描述符的數組【最大為1024個】發給操作系統內核, 讓內核去遍歷,確定哪個文件描述符可以讀寫,實際上只是打了一個標誌,哪些可讀可寫,所以在用戶程式獲取select的返回值的時候,仍然需要遍歷文件描述符的數組具有哪些可處理的事件。

      select模型的優化在於將所有的文件描述符【其實就是正在監聽的socket連接】批量的傳給了內核,降低了系統調用,減少了內核態與用戶態的切換。而select的弊端就在於每次最多只能傳輸1024個文件描述符,這在一些高併發場景【redis緩存】下,仍然是不夠看的。此外select 在內核層仍然是通過遍歷的方式檢查文件描述符的就緒狀態,是個同步過程,只不過無系統調用切換上下文的開銷。
    • poll

      poll對於select來講,最大的區別在於只是將每次只能傳輸1024個文件描述符的限制去掉了
    • epoll

      epoll是在select和poll的基礎上做出的演進。他主要針對以下3點做出了改進
        1.內核中保存一份文件描述符的集合,無需用戶程式每次懂重新傳遞【不需要拷貝】;
        2.內核不再通過輪訓的方式獲取事件就緒的文件描述符,而是通過事件回調的方式將就緒事件放入到一個就緒隊列中【內核程式不需要進行O(N)的遍歷】;
        3.內核僅會將就緒隊列中的文件描述符返回給用戶程式,用戶程式直接處理該描述符對應的事件即可【用戶程式不需要再次進行O(N)的遍歷,內核將不必要的文件描述符過濾了,因此發生的記憶體拷貝更少了】。

    • select、poll、epoll對比

      AIO

      不論是阻塞IO亦或是NIO,它們都是同步IO,即當內核將數據準備好的時候,都是由用戶線程將數據拷貝到用戶空間。除此之外還有一個非同步IO,即非阻塞IO,當數據準備好的時候,不需要用戶線程將數據拷貝到程式的運行空間,而是直接由內核線程完成數據的拷貝。


      參考文件:
      1.徹底搞懂IO多路復用
      2.忘了一些重要的文章~~~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 數組 數組存儲相同類型值的序列。 聲明數組 數組是一種數據結構,用來存儲同一類型值的集合。通過一個整型下標(index,或稱索引)可以訪問數組中的每一個值。例如,如果a是一個整型數組,a[i]就是數組中下標為i的整數。 在聲明數組變數時,需要指出數組類型(數據元素類型緊跟[])和數組變數的名字。下麵 ...
  • 啥是倍增思想? 倍增,每次將範圍擴大或減少一倍而達到加速的效果 舉個慄子,你想要跳到15米遠的地方,你怎麼找到這個15這個地方,一步一步跳嗎,利用倍增的話 預設一個k使2^k>15值 ,這裡我們假設k=5, 2^5=32 >15 k- -; k=4; 跳過了,不跳 2^4=16 >15 k- -; ...
  • 大數 如果基本的整數和浮點數精度不能夠滿足需求,那麼可以使用java.math包中兩個很有用的類:BigInteger和BigDecimal。這兩個類可以處理包含任意長度數字序列的數值。BigInteger類實現任意精度的整數運算,BigDecimal實現任意精度的浮點數運算。 使用靜態的value ...
  • Java 異常機制(也許是全網最獨特視角) 一、Java中的“異常“指什麼 什麼是異常 一句話簡單理解:異常是程式運行中的一些異常或者錯誤。 (純字面意思) Error類 和 Exception類 Java中“萬物皆對象”,異常也不例外, Java把異常當做對象來處理,並將異常分為兩大類——Erro ...
  • 一、業務需求 在工作中遇到一個場景,軟體bug或功能發佈之後,會通知測試進行測試,要求寫一個小工具能自動發送郵件,功能包含發送和抄送支持多個,因為只是通知沒有寫進附件功能,這個其他博客都有搜一下就可以了。 二、以下是實現代碼 這裡要註意如果接收者郵箱三種方式都沒配置則需要手動輸入,其他的沒配置就是彈 ...
  • 值類型 整數,浮點數,布爾值,字元,枚舉,結構體 引用類型 數組,用戶自定義的類,介面,委托,object,字元串 值類型與引用類型的區別: 存放地址不同,值類型存放在棧中,引用類型存放在堆中。 記憶體分佈: 在程式運行時,記憶體分別為四個區域塊,分別是:堆區,棧區,全局區,代碼區 存放函數內的局部變數 ...
  • 類是模板 對象是基於模板生成的實體 Car表示類,car表示變數,new關鍵字,Car()類的構造方法 Car car = new Car(); 構造方法:new欄位後跟的方法,用於創建一個對象 成員變數:類中聲明的變數稱為這個類的成員變數,類的成員變數需要對象.變數 成員方法:類中聲明的方法稱為這 ...
  • 三目運算符一般用在不是是就是否的結果上,和if else用法基本相似但先比較之下代碼量更上,熟悉過後也是比較容易上手的。 三目運算符 點擊查看代碼 // 獲得二者之間的最小值 public int GetMinValue(int numberA,int numberB){ // 含義:`numebr ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...