我有一個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);
...
您使用的是Java和C中相同的隨機數序列?請注意,原始磁盤傳輸速度無關緊要。對於隨機訪問,你需要看看尋求時間。 –
爲什麼寫入40000.java文件給我pocket pocket drive需要8分鐘。與1 mp4的20秒(相同累計尺寸)相比,我扯掉了?我想我的錢退回(對於USB驅動器) – AsConfused
在C中發佈相同測試的代碼,以便讀者可以確定要比較的內容。 –