1. 程式人生 > >為什麼NIO比BIO效率高

為什麼NIO比BIO效率高

原文地址:https://blog.csdn.net/wy0123/article/details/79382761

NIO比BIO效率高,主要原因是什麼呢? 

網上大多給出了兩者的區別,可是具體效率高在哪裡呢。

首先我們看一下各自的特點 
BIO:

  1. socketServer的accept方法是阻塞的。
  2. 當有連線請求時,socketServer通過accept方法獲取一個socket
  3. 取得socket後,將這個socket分給一個執行緒去處理。此時socket需要等待有效的請求資料到來後,才可以真正開始處理請求。
  4. socket交給執行緒後,這時socketServer才可以接收下一個連線請求。
  5. 獲得連線的順序是和客戶端請求到達伺服器的先後順序相關。

NIO:

  1. 基於事件驅動,當有連線請求,會將此連線註冊到多路複用器上(selector)。
  2. 在多路複用器上可以註冊監聽事件,比如監聽accept、read
  3. 通過監聽,當真正有請求資料時,才來處理資料。
  4. 不會阻塞,會不停的輪詢是否有就緒的事件,所以處理順序和連線請求先後順序無關,與請求資料到來的先後順序有關

主要對比

  • BIO一個連線,一個執行緒,非http請求,有可能只連線不發請求資料,此時執行緒是無用浪費的。
  • BIO處理依賴於連線建立;NIO處理依賴於請求資料的到來。導致執行順序不同。

    1. 一個執行緒處理一個請求 
      BIO:連線請求來,建立socket,等待請求資料到來(t1),處理時間(t2) 
      NIO:連線請求來,註冊到selector,設定讀監聽,等待請求資料(t1),處理時間(t2) 
      此時,兩者用時皆為t1+t2,沒有區別
    2. 一個執行緒處理兩個請求 
      第一個請求,等待請求資料(10),處理時間(1) 
      第二個請求,等待請求資料(1),處理時間(2) 
      BIO:用時 10+1+1+2=14,第1個執行完用時10+1,等待第一個執行完處理第2個,用時1+2 
      NIO:用時 1+2+7+1=11, 第二個資料先到,時間 1+2,此時第一個需要等時為10秒,還沒到,還需等待7秒,時間為7+1
    3. 兩個執行緒處理兩個請求 
      第一個請求,等待請求資料(10),處理時間(1) 
      第二個請求,等待請求資料(1),處理時間(2) 
      BIO:用時 10+1+2=13,等待第1個請求10,交給工作執行緒一處理,此時同時接受第2個,等待1秒,處理時間2秒,此間執行緒一處理時間為一秒,線上程二結束之前就已經結束 
      NIO
      :用時 1+2+7+1=11,第二個資料先到,時間 1+2,此時第一個還沒到,還需等待7秒,時間為7+1 
      如果兩個請求順序相反,則bio和nio一樣,都是11秒 
      由此可見由於阻塞等待機制的不同,導致效率不同,主要優化點為,不必排隊等待,先到先處理,就有可能效率高一點。
  • BIO如果想要處理併發請求,則必須使用多執行緒,一般後端會用執行緒池來支援 
    NIO可以使用單執行緒,可以減少執行緒切換上下文的消耗。 
    但是雖然單執行緒減少了執行緒切換的消耗,但是處理也變為線性的,也就是處理完一個請求,才能處理第二個。 
    這時,有這麼兩個場景:

    1. 後端是密集型的計算,沒有大量的IO操作,比如讀些檔案、資料庫等
    2. 後端是有大量的IO操作。

    當為第一種場景時: 
    NIO單執行緒則比較有優勢, 理由是雖然是單執行緒,但是由於執行緒的計算是併發計算,不是平行計算,說到底,計算壓力還是在CPU上,一個執行緒計算,沒有執行緒的多餘消耗,顯然比NIO多執行緒要高效。BIO則必為多執行緒,否則將阻塞到天荒地老,但多執行緒是併發,不是並行,主要還是依靠CPU的線性計算,另外還有處理大量的執行緒上下文。 
    如果為第二種場景,多執行緒將有一定優勢,多個執行緒把等待IO的時間能平均開。此時兩者區別主要取決於以上分析的處理順序了,顯然NIO要更勝一籌。

總結

NIO在接收請求方式上,無疑是要高效於BIO,原因並非是不阻塞,我認為NIO一樣是阻塞的,只是方式不同,先來的有效請求先處理,先阻塞時間短的。此時間可用於等待等待時間長的。 
在處理請求上,NIO和BIO並沒有什麼不同,主要看執行緒池規劃是否和理。NIO相對BIO在密集型計算的模型下,可以用更少的執行緒,甚至單執行緒。