• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • 異步和非阻塞一樣嗎? (內容涉及BIO,NIO,AIO,Netty)

    寫在開頭:

    本文不是純講技術,會涉及概念理解和語義分析的要點。正如博主標題說的,高效的學習方法比擁有多少知識重要。高效的學習方法途徑之一就是閱讀理解,理解能力越好,掌握越快,知識體系更清晰。


    如果剛入門Netty,看過Netty線程模型,又看過JDK的NIO、NIO2,是否困惑于NIO,AIO,阻塞非阻塞的理解?

    Netty目前4.0的版本應該是“非阻塞”的“同步IO”(按照Unix IO模型定義)。之前曾經有版本支持“異步IO”(按照Unix IO模型定義),但是因為某些原因被后來版本移除了。不管Netty是“同步IO”還是“異步IO”(按照Unix IO模型定義),其實我們應用的層面是不需要區分的,因為這是框架底層封裝處理。我們應該僅僅關心是我的業務客戶端代碼調用Netty的API時候客戶端程序是否會停頓等待。


    “不停頓等待”

    廣義的異步,非阻塞,都可以直接理解為正在執行的線程“不停頓等待”.

    當下面業務端main線程執行callNettyApi()時候,不管callNettyApi()執行是否完成,線程繼續運行至callBusinessHandle(),通俗說就是該main方法的線程在執行callBusinessHandle()之前沒有停頓等待callNettyApi()執行結果。

    業務端程序:

    void main(){
    
    callNettyApi(); // 異步?非阻塞?
    
    callBusinessHandle();
    
    }
    
    void callNettyApi(){
    ...
    ...//運行很長時間,例如IO操作
    ...
    }
    

    基于上述的語境,用”不停頓等待”的詞不夠專業,于是很多人專業術語叫”異步”。然后叫”非阻塞”如何呢?其實也對啊,就是在執行callNettyApi()方法時候沒有阻塞main線程。

    至此,作為普通應用開發者調用Netty的API,無非就是關心自己調用的API方法是否讓自己的主線程停頓等待API執行結果,這種場景下是其實不需要考慮異步和非阻塞的區別的,叫異步也好,叫非阻塞也好。也就是廣義的異步和非阻塞等同于”不停頓等待”。

    “停頓等待”

    廣義的同步,阻塞,都可以直接理解為正在執行的線程“停頓等待”.

    這個不詳細舉例說明了,就是上面例子的相反理解就行。


    轉入正題

    文章開始就說了截止到Netty4.0版本是“非阻塞”的“同步IO”(按照Unix IO模型定義),同步與非阻塞矛盾?

    答案是不矛盾。因為這句話要結合具體語境理解。

    首先,在Unix的IO模型里:

    • 異步I/O 是指用戶程序發起IO請求后,不等待數據,同時操作系統內核負責I/O操作把數據從內核拷貝到用戶程序的緩沖區后通知應用程序。數據拷貝是由操作系統內核完成,用戶程序從一開始就沒有等待數據,發起請求后不參與任何IO操作,等內核通知完成。

    • 同步I/O 就是非異步IO的情況,也就是用戶程序要參與把數據拷貝到程序緩沖區(例如java的InputStream讀字節流過程)。

    • 同步IO里的非阻塞 是指用戶程序發起IO操作請求后不等待數據,而是調用會立即返回一個標志信息告知條件不滿足,數據未準備好,從而用戶請求程序繼續執行其它任務。執行完其它任務,用戶程序會主動輪詢查看IO操作條件是否滿足,如果滿足,則用戶程序親自參與拷貝數據動作。

    這里寫圖片描述

    這里寫圖片描述

    簡單說,Unix IO模型的語境下,同步和異步的區別在于數據拷貝階段是否需要完全由操作系統處理。阻塞和非阻塞操作是針對發起IO請求操作后是否有立刻返回一個標志信息而不讓請求線程等待。基于這個語境,Netty目前的版本是沒有把IO操作交過操作系統處理的,所以是屬于同步的。對于網上大部分文章,如果別人說Netty是異步非阻塞,如果要深究,那真要看看Netty新的版本是否把IO操作交過操作系統處理,或者看看有否使用JDK1.7中的AIO API,否則他們說的異步其實是指客戶端程序調用Netty的IO操作API“不停頓等待”

    =====

    其次,在Java的IO模型里:
    JDK的各個歷史版本引入如下概念。
    BIO: Blocking IO
    NIO:Non Blocking IO 或者 New IO
    AIO:Asynchronous IO 或者 NIO2

    這里的AIO應該就對應著Unix模型里的異步IO,也就是IO操作交給操作系統處理,充分調用OS參與并發操作,確實是操作系統的異步IO機制。

    而BIO和NIO簡單對比就是,NIO解決了BIO的痛點,把BIO中請求IO過程中的兩步(請求連接+連接有真實IO請求時候的處理過程)分離開來,不讓一個線程負責這兩步。NIO就是一個線程負責所有請求連接但不處理IO操作,該線程只負責把連接注冊到多路復用器上,多用復用器輪詢到連接有IO請求時候再啟動其它線程處理IO請求操作。

    注意一點,Netty線程模型提及很多IO線程池,每條IO線程在進行IO操作(IO條件滿足進行真正讀寫數據)時候雖然也是要消耗操作時間,但這種情況是否應該叫阻塞,取決于該IO線程有沒有阻塞業務請求線程,當且僅當所有的IO線程在重度負載情形下(IO線程池所有IO線程在工作)導致業務請求線程提交不了新請求的情形下才叫IO線程的IO操作阻塞了業務線程的IO請求。由此可知,NIO也會產生BIO的情況。


    啟示

    平時項目里,溝通效率低效,往往也是不同的人描述不同的東西時候用了相同的詞匯,或者相同的東西卻用了不同的詞匯,這都會造成雙方理解困難。要高效溝通,其中途徑之一就是統一概念叫法。不允許重要而難懂的概念被隨意指代。

    延伸, 那么你是否好奇程序如何實現非阻塞的?

    建議看看Java的Future模式實現和JDK并發包里的Future工具庫。IO操作不阻塞用戶請求線程,編程可以使用Future模式實現。

    結束語

    希望本文幫你理解清楚這些概念,然后隨心應用Netty或者進行網絡編程,無所顧慮自己的困惑影響到程序編寫的正確性。


    參考文章:
    Java I/O模型從BIO到NIO和Reactor模式
    BIO與NIO、AIO的區別(這個容易理解)
    Netty系列之Netty線程模型
    Netty中,耗時的業務邏輯代碼應該寫在哪?
    JDK7+的NIO2.0中的AIO例子

    版權聲明:本文為matthew_zhang原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/matthew_zhang/article/details/71328697

    智能推薦

    Netty一:Java bio nio

    Java支持的I/O模型 Java共支持3種網絡編程模型/IO模式:BIO、NIO、AIO JavaBIO:同步并阻塞(傳統阻塞型),服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷 JavaNIO:同步非阻塞,服務器實現模式為一個線程處理多個請求(連接),即客戶端發送的連接請求都會注冊到多路復用器上,多路復用...

    HTML中常用操作關于:頁面跳轉,空格

    1.頁面跳轉 2.空格的代替符...

    freemarker + ItextRender 根據模板生成PDF文件

    1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...

    電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!

    Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...

    requests實現全自動PPT模板

    http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...

    猜你喜歡

    Linux C系統編程-線程互斥鎖(四)

    互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...

    統計學習方法 - 樸素貝葉斯

    引入問題:一機器在良好狀態生產合格產品幾率是 90%,在故障狀態生產合格產品幾率是 30%,機器良好的概率是 75%。若一日第一件產品是合格品,那么此日機器良好的概率是多少。 貝葉斯模型 生成模型與判別模型 判別模型,即要判斷這個東西到底是哪一類,也就是要求y,那就用給定的x去預測。 生成模型,是要生成一個模型,那就是誰根據什么生成了模型,誰就是類別y,根據的內容就是x 以上述例子,判斷一個生產出...

    styled-components —— React 中的 CSS 最佳實踐

    https://zhuanlan.zhihu.com/p/29344146 Styled-components 是目前 React 樣式方案中最受關注的一種,它既具備了 css-in-js 的模塊化與參數化優點,又完全使用CSS的書寫習慣,不會引起額外的學習成本。本文是 styled-components 作者之一 Max Stoiber 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...

    基于TCP/IP的網絡聊天室用Java來實現

    基于TCP/IP的網絡聊天室實現 開發工具:eclipse 開發環境:jdk1.8 發送端 接收端 工具類 運行截圖...

    精品国产乱码久久久久久蜜桃不卡