要問技術多NB,請問IO模型知多少? | 上篇

圖片

 1   引言程序員

同步異步I/O,阻塞非阻塞I/O是程序員老生常談的話題了,也是本身一直以來懵懵懂懂的一個話題。好比:何爲同步異步?何爲阻塞與非阻塞?兩者的區別在哪裏?阻塞在何處?爲何會有多種IO模型,分別用來解決問題?各類IO模型的優劣勢在哪裏,適用於何種應用場景?經常使用的框架採用的是何種I/O模型?數據庫

 2   定義
緩存

2. I/O 的定義安全

在計算機系統中I/O就是輸入(Input)和輸出(Output)的意思,針對不一樣的操做對象,能夠劃分爲磁盤I/O模型,網絡I/O模型,內存映射I/O, Direct I/O、數據庫I/O等,只要具備輸入輸出類型的交互系統均可以認爲是I/O系統,也能夠說I/O是整個操做系統數據交換與人機交互的通道,這個概念與選用的開發語言沒有關係,是一個通用的概念。服務器

2.1. 計算機視角網絡

在現在的系統中I/O卻擁有很重要的位置,如今系統都有可能處理大量文件,大量數據庫操做,而這些操做都依賴於系統的I/O性能,也就形成了如今系統的瓶頸每每都是因爲I/O性能形成的。所以,爲了解決磁盤I/O性能慢的問題,系統架構中添加了緩存來提升響應速度;或者有些高端服務器從硬件級入手,使用了固態硬盤(SSD)來替換傳統機械硬盤;在大數據方面,Spark愈來愈多的承擔了實時性計算任務,而傳統的Hadoop體系則大多應用在了離線計算與大量數據存儲的場景,這也是因爲磁盤I/O性能遠不如內存I/O性能而形成的格局(Spark更多的使用了內存,而MapReduece更多的使用了磁盤)。此,一個系統的優化空間,每每都在低效率的I/O環節上,不多看到一個系統CPU、內存的性能是其整個系統的瓶頸。也正由於如此,Java在I/O上也一直在作持續的優化,從JDK 1.4開始便引入了NIO模型,大大的提升了以往BIO模型下的操做效率多線程

因此I/O之於計算機,有兩層意思:架構

  1. I/O設備併發

  2. 對I/O設備的數據讀寫app

對於一次I/O操做,必然涉及2個參與方,一個輸入端,一個輸出端,而又根據參與雙方的設備類型,咱們又能夠分爲磁盤I/O,網絡I/O(一次網絡的請求響應,網卡)等。

2.2. 程序視角

應用程序做爲一個文件保存在磁盤中,只有加載到內存到成爲一個進程才能運行。應用程序運行在計算機內存中,必然會涉及到數據交換,好比讀寫磁盤文件,訪問數據庫,調用遠程API等等。但咱們編寫的程序並不能像操做系統內核同樣直接進行I/O操做。

但操做系統向外提供API,其由各類類型的系統調用(System Call)組成,以提供安全的訪問控制。因此應用程序要想訪問內核管理的I/O,必須經過調用內核提供的系統調用(system call)進行間接訪問。

因此I/O之於應用程序來講,強調的經過向內核發起系統調用完成對I/O的間接訪問。換句話說應用程序發起的一次IO操做實際包含兩個階段:

  1. IO調用階段:應用程序進程向內核發起系統調用

  2. IO執行階段:內核執行IO操做並返回

    • 準備數據階段:內核等待I/O設備準備好數據

    • 拷貝數據階段:將數據從內核緩衝區拷貝到用戶空間緩衝區

怎麼理解準備數據階段呢?對於寫請求:等待系統調用的完整請求數據,並寫入內核緩衝區;對於讀請求:等待系統調用的完整請求數據;(若請求數據不存在於內核緩衝區)則將外圍設備的數據讀入到內核緩衝區。

而應用程序進程在發起IO調用至內核執行IO返回以前,應用程序進程/線程所處狀態,就是咱們下面要討論的第二個話題阻塞IO與非阻塞IO。

 3   IO 模型之阻塞 I/O(BIO)

應用程序中進程在發起IO調用後至內核執行IO操做返回結果以前,若發起系統調用的線程一直處於等待狀態,則這次IO操做爲阻塞IO。阻塞IO簡稱BIO,Blocking IO。其處理流程以下圖所示:

圖片

從上圖可知當用戶進程發起IO系統調用後,內核從準備數據到拷貝數據到用戶空間的兩個階段期間用戶調用線程選擇阻塞等待數據返回。

所以BIO帶來了一個問題:若是內核數據須要耗時好久才能準備好,那麼用戶進程將被阻塞,浪費性能。爲了提高應用的性能,雖然能夠經過多線程來提高性能,但線程的建立依然會藉助系統調用,同時多線程會致使頻繁的線程上下文的切換,一樣會影響性能。因此要想解決BIO帶來的問題,咱們就得看到問題的本質,那就是阻塞二字。

 4   IO 模型之阻塞 I/O(NIO)

那解決方案天然也容易想到,將阻塞變爲非阻塞,那就是用戶進程在發起系統調用時指定爲非阻塞,內核接收到請求後,就會當即返回,而後用戶進程經過輪詢的方式來拉取處理結果。也就是以下圖所示:

圖片

應用程序中進程在發起IO調用後至內核執行IO操做返回結果以前,若發起系統調用的線程不會等待而是當即返回,則這次IO操做爲非阻塞IO模型。非阻塞IO簡稱NIO,Non-Blocking IO。

然而,非阻塞IO雖然相對於阻塞IO大幅提高了性能,但依舊不是完美的解決方案,其依然存在性能問題,也就是頻繁的輪詢致使頻繁的系統調用,會耗費大量的CPU資源。好比當併發很高時,假設有1000個併發,那麼單位時間循環內將會有1000次系統調用去輪詢執行結果,而實際上可能只有2個請求結果執行完畢,這就會有998次無效的系統調用,形成嚴重的性能浪費。有問題就要解決,那NIO問題的本質就是頻繁輪詢致使的無效系統調用

相關文章
相關標籤/搜索