異步和非阻塞一樣嗎? (內容涉及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例子
智能推薦
Netty一:Java bio nio
Java支持的I/O模型 Java共支持3種網絡編程模型/IO模式:BIO、NIO、AIO JavaBIO:同步并阻塞(傳統阻塞型),服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷 JavaNIO:同步非阻塞,服務器實現模式為一個線程處理多個請求(連接),即客戶端發送的連接請求都會注冊到多路復用器上,多路復用...
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 所寫,首先總結了前端組件化樣式中的最佳實踐原則,然后在此基...