2015-06-27 24 views
4

我有一個SSD磁盤,每個規範應該提供不少於10k IOPS。我的基準證實它可以給我20k IOPS。爲什麼Java磁盤I/O執行速度比用C編寫的等效I/O代碼慢?

然後,我創建這樣一個測試:

private static final int sector = 4*1024; 
private static byte[] buf = new byte[sector]; 
private static int duration = 10; // seconds to run 
private static long[] timings = new long[50000]; 
public static final void main(String[] args) throws IOException { 
    String filename = args[0]; 
    long size = Long.parseLong(args[1]); 
    RandomAccessFile raf = new RandomAccessFile(filename, "r"); 
    Random rnd = new Random(); 
    long start = System.currentTimeMillis(); 
    int ios = 0; 
    while (System.currentTimeMillis()-start<duration*1000) { 
     long t1 = System.currentTimeMillis(); 
     long pos = (long)(rnd.nextDouble()*(size>>12)); 
     raf.seek(pos<<12); 
     int count = raf.read(buf); 
     timings[ios] = System.currentTimeMillis() - t1; 
     ++ios; 
    } 
    System.out.println("Measured IOPS: " + ios/duration); 
    int totalBytes = ios*sector; 
    double totalSeconds = (System.currentTimeMillis()-start)/1000.0; 
    double speed = totalBytes/totalSeconds/1024/1024; 
    System.out.println(totalBytes+" bytes transferred in "+totalSeconds+" secs ("+speed+" MiB/sec)"); 
    raf.close(); 
    Arrays.sort(timings); 
    int l = timings.length; 
    System.out.println("The longest IO = " + timings[l-1]); 
    System.out.println("Median duration = " + timings[l-(ios/2)]); 
    System.out.println("75% duration = " + timings[l-(ios * 3/4)]); 
    System.out.println("90% duration = " + timings[l-(ios * 9/10)]); 
    System.out.println("95% duration = " + timings[l-(ios * 19/20)]); 
    System.out.println("99% duration = " + timings[l-(ios * 99/100)]); 
} 

然後我運行這個例子,得到的只是2186個IOPS:

$ sudo java -cp ./classes NioTest /dev/disk0 240057409536 
Measured IOPS: 2186 
89550848 bytes transferred in 10.0 secs (8.540234375 MiB/sec) 
The longest IO = 35 
Median duration = 0 
75% duration = 0 
90% duration = 0 
95% duration = 0 
99% duration = 0 

爲什麼它的工作這麼慢得多比用C相同的測試?

更新:這裏是Python代碼這給20K IOPS:

def iops(dev, blocksize=4096, t=10): 

    fh = open(dev, 'r') 
    count = 0 
    start = time.time() 
    while time.time() < start+t: 
     count += 1 
     pos = random.randint(0, mediasize(dev) - blocksize) # need at least one block left 
     pos &= ~(blocksize-1) # sector alignment at blocksize 
     fh.seek(pos) 
     blockdata = fh.read(blocksize) 
    end = time.time() 
    t = end - start 
    fh.close() 

UPDATE2:NIO代碼(只是一塊,不會複製所有的方法)

... 
RandomAccessFile raf = new RandomAccessFile(filename, "r"); 
InputStream in = Channels.newInputStream(raf.getChannel()); 
... 
int count = in.read(buf); 
... 
+2

您使用的是Java和C中相同的隨機數序列?請注意,原始磁盤傳輸速度無關緊要。對於隨機訪問,你需要看看尋求時間。 –

+4

爲什麼寫入40000.java文件給我pocket pocket drive需要8分鐘。與1 mp4的20秒(相同累計尺寸)相比,我扯掉了?我想我的錢退回(對於USB驅動器) – AsConfused

+3

在C中發佈相同測試的代碼,以便讀者可以確定要比較的內容。 –

回答

7

你的問題是基於一個錯誤的假設C代碼類似於Java代碼將執行以及IOMeter的呢。由於這個假設是錯誤的,所以C性能和Java性能之間沒有差異來解釋。

如果您的問題是您的Java代碼相對於IOMeter表現如此糟糕的原因,那麼答案就是IOMeter不會像您的代碼那樣一次發出一個請求。要獲得SSD的完整性能,您需要保持其請求隊列非空,並等待每次讀取完成,然後再發出下一個不可能做到的事情。

嘗試使用線程池發出您的請求。

0

因爲你正在使用RandomAccessFile,這是Java中磁盤I/O最慢的方法之一。

嘗試使用更快的東西,如BufferedInputStreamBufferedOutputStream,並查看速度。

如果你想知道爲什麼這會對SSD產生影響(因爲SSD應該擅長隨機訪問),這不是關於訪問的隨機性;這是關於帶寬。如果你有一個總線寬度爲1024位的固態硬盤,但你每寫入一次只能寫入64位數據(正如你通過寫入longdouble s所做的那樣),你將會得到很慢的速度。 (當然,這些數字僅僅是爲了舉例的目的。)

現在,我可以看到,這不是你的代碼在做什麼(或者至少,似乎在做),但它很可能是RandomAccessFile實現它引擎蓋下的方式。再次嘗試使用緩衝流,看看會發生什麼。

+0

複製操作mentiont我沒有記憶2TiB使用的BufferedInputStream – Antonio

+1

從什麼時候'BufferedInputStream'需要2 TB的內存? –

+1

你碰巧知道的BufferedInputStream是順序讀取(和我的測試是隨機讀取)? – Antonio

3

從這篇文章中可以看出,傳統的Java隨機訪問速度是2.5到3.5倍。這是一個研究pdf,所以不要責怪我點擊它。

鏈接:http://pages.cs.wisc.edu/~guo/projects/736.pdf

爪哇原始I/O比C/C++慢,因爲系統中的Java調用是 更昂貴;緩衝提高了Java I/O性能,因爲它減少了系統調用,但對於較大的緩衝區大小沒有什麼大的收益;因爲用戶可以根據自己的需要來定製它,所以直接緩衝比Java提供的緩衝I/O類更好。增加 操作大小有助於I/O性能,而無需管理費用;並且系統 調用在Java本地方法中便宜,而調用 本地方法的開銷相當高。當本地調用的數量正確減少時,可以實現與C/C++相當的性能。

從那個時代就是你的代碼。現在讓我們改寫它不是使用RandomAccessFile而是java.nio我們應該嗎?

我有一些NIO2代碼,我們可以對坑C.垃圾收集可以排除:)

+0

我相信我做錯了什麼。我無法弄清楚什麼是錯的。我嘗試過NIO,但得到相同的IOPS。如果您可以提出替代代碼,將會非常感激。 – Antonio

+0

這不會是快,但它不會是 – Drew

+0

3.5倍慢我以前做的彙編和C唯一讓我不妄想。那麼,大部分不是。 – Drew