阻塞IO和非阻塞IO的區別


轉載地址:

http://blog.sina.com.cn/s/blog_a46817ff0101g0gv.html

http://blog.csdn.net/nodeathphoenix/article/details/30389317

 

有很多人把阻塞認為是同步,把非阻塞認為是異步;個人認為這樣是不准確的,當然從思想上可以這樣類比,但方式是完全不同的,下面說說在JAVA里面阻塞IO和非阻塞IO的區別

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

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

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

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

雖然說,非阻塞IO比阻塞IO有更高的性能,但是對於開發來的,難度就成數倍遞增了。由於是有多少數據就讀取多少數據,這樣在讀取完整之前需要將已經讀取到的數據保存起來,而且需要與其他地方來的數據隔離開來不能混在一起,否則就不知道這數據是誰的了

 

區別:
讀:
讀本質來說其實不能是讀,在實際中, 具體的接收數據不是由這些調用來進行,是由於系統底層自動完成的。read也好,recv也好只負責把數據從底層緩沖copy到我們指定的位置。

  在阻塞條件下,如果沒有發現數據在網絡緩沖中會一直等待,當發現有數據的時候會把數據讀到用戶指定的緩沖區。但是如果這個時候讀到的數據量比較少,比參數中指定的長度要小,read並不會一直等待下去,而是立刻返回。read的原則是數據在不超過指定的長度的時候有多少讀多少,沒有數據就會一直等待。所以一般情況下我們讀取數據都需要采用循環讀的方式讀取數據,一次read完畢不能保證讀到我們需要長度的數據,read完一次需要判斷讀到的數據長度再決定是否還需要再次讀取。

  在非阻塞的情況下,read的行為是如果發現沒有數據就直接返回,如果發現有數據那么也是采用有多少讀多少的進行處理.對於讀而言,阻塞和非阻塞的區別在於沒有數據到達的時候是否立刻返回。
recv中有一個MSG_WAITALL的參數 recv(sockfd, buff, buff_size, MSG_WAITALL)。在正常情況下 recv是會等待直到讀取到buff_size長度的數據,但是這里的WAITALL也只是盡量讀全,在有中斷的情況下recv還是可能會被打斷,造成沒有讀完指定的buff_size的長度。所以即使是采用recv + WAITALL參數還是要考慮是否需要循環讀取的問題,在實驗中對於多數情況下recv還是可以讀完buff_size,所以相應的性能會比直接read進行循環讀要好一些。不過要注意的是這個時候的sockfd必須是處於阻塞模式下,否則WAITALL不能起作用。


寫:
寫的本質也不是進行發送操作,而是把用戶態的數據copy到系統底層去,然后再由系統進行發送操作,返回成功只表示數據已經copy到底層緩沖,而不表示數據以及發出,更不能表示對端已經接收到數據。

  在阻塞的情況,是會一直等待直到write完全部的數據再返回。這點行為上與讀操作有所不同,究其原因主要是讀數據的時候,通常剛開始我們並不知道要讀的數據的長度,而是在數據的頭部設置了一個長度,在讀完指定長度的頭部后,才知道整個要讀的數據長度。如果一開始就貿然設置一個要讀的數據長度,然后像阻塞的write那樣去等讀完,則很可能會造成死循環;而對於write,由於需要寫的長度是已知的,所以可以一直再寫,直到寫完.不過問題是write是可能被打斷造成write一次只write一部分數據,所以write的過程還是需要考慮循環write, 只不過多數情況下一次write調用就可能成功。
  

  非阻塞寫的情況,是采用可以寫多少就寫多少的策略。與讀不一樣的地方在於,有多少讀多少是由網絡發送端是否有數據傳輸到本地內核緩存為准。但是對於可以寫多少是由本地的網絡堵塞情況為標准的,在網絡阻塞嚴重的時候,網絡層沒有足夠的內存來進行寫操作,這時候就會出現寫不成功的情況,阻塞情況下會盡可能(有可能被中斷)等待到數據全部發送完畢, 對於非阻塞的情況就是一次寫多少算多少,沒有中斷的情況下也還是會出現write到一部分的情況。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM