阻塞式和非阻塞式IO

有不少人把阻塞認爲是同步,把非阻塞認爲是異步;我的認爲這樣是不許確的,固然從思想上能夠這樣類比,但方式是徹底不一樣的,下面說說在JAVA裏面阻塞IO和非阻塞IO的區別java

     在JDK1.4中引入了一個NIO的類庫,使得Java涉及IO的操做擁有阻塞式和非阻塞式兩種,問一下阻塞IO與非阻塞IO有什麼區別?有什麼優缺點?linux

在阻塞模式下,若從網絡流中讀取不到指定大小的數據量,阻塞IO就在那裏阻塞着。好比,已知後面會有10個字節的數據發過來,可是我如今只收到8個字節,那麼當前線程就在那傻傻地等到下一個字節的到來,對,就在那等着,啥事也不作,直到把這10個字節讀取完,這纔將阻塞放開通行。編程

在非阻塞模式下,若從網絡流中讀取不到指定大小的數據量,非阻塞IO就當即通行。好比,已知後面會有10個字節的數據發過來,可是我如今只收到8個字節,那麼當前線程就讀取這8個字節的數據,讀完後就當即返回,等另外兩個字節再來的時候再去讀取。服務器

從上面能夠看出,阻塞IO在性能方面是很低下的,若是要使用阻塞IO完成一個Web服務器的話,那麼對於每個請求都必須啓用一個線程進行處理。而使用非阻塞IO的話,一到兩個線程基本上就夠了,由於線程不會產生阻塞,比如一下接收A請求的數據,另外一下接收B請求的數據,等等,就是不停地東奔西跑,直接到把數據接收完了。網絡

雖說,非阻塞IO比阻塞IO有更高的性能,可是對於開發來的,難度就成數倍遞增了。因爲是有多少數據就讀取多少數據,這樣在讀取完整以前須要將已經讀取到的數據保存起來,並且須要與其餘地方來的數據隔離開來不能混在一塊兒,不然就不知道這數據是誰的了,呵呵。多線程

 

咱們都知道TCP是面向鏈接的傳輸層協議,一個socket一定會有綁定一個鏈接,在普通的BIO(阻塞式IO)中,須要有三次握手,而後通常的socket編程就是這樣的形式。異步

Socket服務器端流程以下:加載套接字->建立監聽的套接字->綁定套接字->監聽套接字->處理客戶端相關請求。socket

Socket客戶端一樣須要先加載套接字,而後建立套接字,不過以後不用綁定和監聽了,而是直接鏈接服務器,發送相關請求。性能

 

 

 

       他們一直就佔用這個鏈接,若是有信息發送,那麼就響應,不然就一直阻塞着。若是有多鏈接,那麼就要使用多線程,一個線程處理一個鏈接,在鏈接還少的狀況下,是容許的,但若是同時處理的鏈接過多好比說1000,那麼在win平臺上就會遇到瓶頸了若是2000,那麼在linux上就遇到瓶頸了,由於在不一樣的平臺上每個進程可以建立的線程數是有限度的,而且過多的線程必將會引發系統對線程調度的效率問題,再怎麼也要保證線程優先隊列,阻塞隊列;假設一千個線程,一個線程最少一兆的棧大小,對內存也是一個很大的消耗。spa

 

       總之阻塞式的IO是:一鏈接<一一一>一線程 

 

       而後出現了NIO,在java1.4引入了java.nio包,java new I/O。引入了操做系統中經常使用的緩衝區和通道等概念。

 

       緩衝區: 在操做系統中緩衝區是爲了解決CPU的計算速度和外設輸入輸出速度不匹配的問題,由於外設太慢了,若是沒有緩衝區,那麼CPU在外設輸入的時候就要一直等着,就會形成CPU處理效率的低下,引入了緩衝以後,外設直接把數據放到緩衝中,當數據傳輸完成以後,給CPU一箇中斷信號,通知CPU:「個人數據傳完了,你本身從緩衝裏面去取吧」。若是是輸出也是同樣的道理。

 

       通道: 那麼通道用來作什麼呢?其實從他的名字就能夠看出,它就是一條通道,您想傳遞出去的數據被放置在緩衝區中,而後緩衝區中怎麼從哪裏傳輸出去呢?或者外設怎麼把數據傳輸到緩衝中呢?這裏就要用到通道。它能夠進一步的減小CPU的干預,同時更有效率的提升整個系統的資源利用率,例如當CPU要完成一組相關的讀操做時,只須要向I/O通道發送一條指令,以給出其要執行的通道程序的首地址和要訪問的設備,通道執行通道程序即可以完成CPU指定的I/O任務。

 

      選擇器: 另一項創新是選擇器,當咱們使用通道的時候也許通道沒有準備好,或者有了新的請求過來,或者線程遇到了阻塞,而選擇器偏偏能夠幫助CPU瞭解到這些信息,但前提是將這個通道註冊到了這個選擇器。

下面一個例子是我看過的一個講述的很貼切的例子:

一輛從 A 開往 B 的公共汽車上,路上有不少點可能會有人下車。司機不知道哪些點會有哪些人會下車,對於須要下車的人,如何處理更好?

1. 司機過程當中定時詢問每一個乘客是否到達目的地,如有人說到了,那麼司機停車,乘客下車。 ( 相似阻塞式 )

2. 每一個人告訴售票員本身的目的地,而後睡覺,司機只和售票員交互,到了某個點由售票員通知乘客下車。 ( 相似非阻塞 )

很顯然,每一個人要到達某個目的地能夠認爲是一個線程,司機能夠認爲是 CPU 。在阻塞式裏面,每一個線程須要不斷的輪詢,上下文切換,以達到找到目的地的結果。而在非阻塞方式裏,每一個乘客 ( 線程 ) 都在睡覺 ( 休眠 ) ,只在真正外部環境準備好了才喚醒,這樣的喚醒確定不會阻塞。
相關文章
相關標籤/搜索