Java: 擴大字節緩存區的大小,提升AIO的處理性能(並發性能)


前些日了,對AIO與NIO的並發性能進行了比較,在低並發的情況下,NIO性能表現比AIO好一些,主要原因是,NIO中可以使用FileChannel.transferTo(long position, long count, WritableByteChannel target),這個方法可以對傳輸文件數據有很大的性能提升。

 

在AIO中,沒辦法使用FileChannel.transferTo(...),只能使用ByteBuffer來做中轉,我一開始使用的ByteBuffer.allocate(16 * 1024),也就是16KB的緩存區。

 

由於上面的原因,所以NIO在不是很高的並發情況下,性能比AIO表現的好一些。

 

昨天,我還寫了一篇文章:AsynchronousFileChannel 使用的默認線程池的疑問

 

今天早上,我試着將ByteBuffer由原來固定的16KB,更改為一個與傳輸的文件大小有關的字節緩存區。

 

相關代碼如下:

 

 //如果文件大小<1M,直接返回一個 fileSize + headerSize
 //如果文件大小>=1M,直接返回一個(fileSize + headerSize) / 2, 也就是最多保證分兩次傳輸完數據
 private ByteBuffer allocateByteBuffer(int fileSize, int headerSize)
 {
  if(fileSize < 1024 * 1024)
  {
   return ByteBuffer.allocate(fileSize + headerSize);
  }
  else
  {
   return ByteBuffer.allocate((fileSize + headerSize) / 2 + 1); //這所以 +1, 因為 11 / 2 = 5,為了保證兩次傳完, + 1 可保證這一點
  }
 }

 

然后經過測試發現,在低並發情況下,性能上升了很多,終於趕上了NIO的性能,同時觀察“任務管理器”中的進程使用的線程數也下降了很多,真是一舉兩得,這讓我興奮了好一會兒,

 

經過冷靜的分析,我得出的結論:

 

之所以將ByteBuffer的大小設置為與傳輸的文件大小有關的緩存區后性能得到了很大的提升,主要與AIO的“寫操作”有關。

 

舉個例子:

在AIO的“寫操作”中,如果我們設置ByteBuffer為一個固定的16KB的緩存區,當我們傳輸一個160KB的文件時,AIO的“寫操作”需要執行10次“回調”。每1次的回調都是在系統默認的一個線程池中運行的,回調的次數與線程池中的線程數是成正比的。

 

如是我們將ByteBuffer設置為160KB,在進行AIO的“寫操作”時,系統只執行了一次“回調”,回調的次數減少了,線程池的容量也不再需要那么多了,性能同時也上升了。

 

不過,經過測試也發現,ByteBuffer的容量也不能無限制的根據文件大小一設置,如果一個文件超過1M,還是最好設置為最大不超過1M的緩存區比較好,因為測試發現,如果設置一個很大的緩存區,比如5M,在高並發的時候,系統內存會很快用完,直接拋出: OutOfMemoryError

 

-------------------------------------------------------------------------------------------------

 

AIO進程占用的線程數與文件IO和網絡IO有非常大的關系,當高並發的時候,網絡IO達到瓶頸,這個時候很多任務都沒有完成(正在完成中),占用的線程自然就會不斷的上升。

 

 

2012-07-10

 


免責聲明!

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



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