我正在编写一个应用程序来处理来自二进制文件(最多 50 兆)的大量整数。我需要尽快完成,主要的性能问题是磁盘访问时间,因为我从磁盘进行大量读取,优化读取时间通常会提高应用程序的性能。
到目前为止,我认为我将文件拆分成的块越少(即读取次数越少/读取大小越大),我的应用程序应该运行得越快。这是因为 HDD 由于其机械特性而在寻找(即定位块的开头)时非常慢。但是,一旦它定位到您要求它读取的块的开头,它应该会相当快地执行实际读取。
好吧,直到我运行了这个测试:
旧测试已删除,由于 HDD 缓存而出现问题
新测试(硬盘缓存在这里没有帮助,因为文件太大(1gb)并且我访问其中的随机位置):
int mega = 1024 * 1024;
int giga = 1024 * 1024 * 1024;
byte[] bigBlock = new byte[mega];
int hundredKilo = mega / 10;
byte[][] smallBlocks = new byte[10][hundredKilo];
String location = "C:\\Users\\Vladimir\\Downloads\\boom.avi";
RandomAccessFile raf;
FileInputStream f;
long start;
long end;
int position;
java.util.Random rand = new java.util.Random();
int bigBufferTotalReadTime = 0;
int smallBufferTotalReadTime = 0;
for (int j = 0; j < 100; j++)
{
position = rand.nextInt(giga);
raf = new RandomAccessFile(location, "r");
raf.seek((long) position);
f = new FileInputStream(raf.getFD());
start = System.currentTimeMillis();
f.read(bigBlock);
end = System.currentTimeMillis();
bigBufferTotalReadTime += end - start;
f.close();
}
for (int j = 0; j < 100; j++)
{
position = rand.nextInt(giga);
raf = new RandomAccessFile(location, "r");
raf.seek((long) position);
f = new FileInputStream(raf.getFD());
start = System.currentTimeMillis();
for (int i = 0; i < 10; i++)
{
f.read(smallBlocks[i]);
}
end = System.currentTimeMillis();
smallBufferTotalReadTime += end - start;
f.close();
}
System.out.println("Average performance of small buffer: " + (smallBufferTotalReadTime / 100));
System.out.println("Average performance of big buffer: " + (bigBufferTotalReadTime / 100));
结果:小缓冲区的平均值 - 35 毫秒 大缓冲区的平均值 - 40 毫秒?!(在 linux 和 windows 上试过,在这两种情况下,更大的块大小会导致更长的读取时间,为什么?)
多次运行此测试后,我意识到由于某种神奇的原因,读取一个大块平均比顺序读取 10 个较小大小的块花费的时间更长。我认为这可能是由于 Windows 过于聪明并试图优化其文件系统中的某些内容,所以我在 Linux 上运行了相同的代码,令我惊讶的是,我得到了相同的结果。
我不知道为什么会发生这种情况,有人可以给我提示吗?在这种情况下,最好的块大小是多少?
亲切的问候