我正在尝试使用Java 5.0 x64(在Windows XP上)执行大文件(~4GB)的一次性读取。
最初文件读取速度非常快,但吞吐量逐渐减慢,随着时间的推移,我的机器似乎反应迟钝。
我使用ProcessExplorer来监控文件I / O统计信息,看起来这个过程最初读取的速度为500MB /秒,但这个速率会逐渐下降到20MB /秒左右。
有关维护文件I / O速率的最佳方法的任何想法,尤其是使用Java读取大型文件时?
这是一些测试代码,显示“间隔时间”继续增加。只需传递一个至少500MB的文件。
import java.io.File;
import java.io.RandomAccessFile;
public class MultiFileReader {
public static void main(String[] args) throws Exception {
MultiFileReader mfr = new MultiFileReader();
mfr.go(new File(args[0]));
}
public void go(final File file) throws Exception {
RandomAccessFile raf = new RandomAccessFile(file, "r");
long fileLength = raf.length();
System.out.println("fileLen: " + fileLength);
raf.close();
long startTime = System.currentTimeMillis();
doChunk(0, file, 0, fileLength);
System.out.println((System.currentTimeMillis() - startTime) + " ms");
}
public void doChunk(int threadNum, File file, long start, long end) throws Exception {
System.out.println("Starting partition " + start + " to " + end);
RandomAccessFile raf = new RandomAccessFile(file, "r");
raf.seek(start);
long cur = start;
byte buf[] = new byte[1000];
int lastPercentPrinted = 0;
long intervalStartTime = System.currentTimeMillis();
while (true) {
int numRead = raf.read(buf);
if (numRead == -1) {
break;
}
cur += numRead;
if (cur >= end) {
break;
}
int percentDone = (int)(100.0 * (cur - start) / (end - start));
if (percentDone % 5 == 0) {
if (lastPercentPrinted != percentDone) {
lastPercentPrinted = percentDone;
System.out.println("Thread" + threadNum + " Percent done: " + percentDone + " Interval time: " + (System.currentTimeMillis() - intervalStartTime));
intervalStartTime = System.currentTimeMillis();
}
}
}
raf.close();
}
}
谢谢!
答案 0 :(得分:10)
我非常怀疑你真的每秒从你的磁盘获得500MB。有可能是操作系统缓存了数据 - 而且当真正击中磁盘时,每秒20MB就会发生这种情况。
这很可能在Vista资源管理器的磁盘部分中可见 - 而低技术的方法是监听磁盘驱动器:)
答案 1 :(得分:1)
根据您的具体硬件和正在发生的其他情况,您可能需要合理努力才能做到超过20MB /秒。
我想也许你真的不怎么完全超出规模500MB /秒......
你有什么希望,并且你检查过你的特定驱动器在理论上是否具备它的能力?
答案 2 :(得分:1)
Java垃圾收集器可能成为瓶颈。
我会使缓冲区更大并且是类的私有,因此它被重用而不是每次调用doChunk()时分配。
public class MultiFileReader {
private byte buf[] = new byte[256*1024];
...
}
答案 3 :(得分:0)
您可以使用JConsole监控您的应用,包括内存使用情况。 500 MB /秒听起来很不错。
有关所使用的实现和VM参数的更多信息会有所帮助。
答案 4 :(得分:0)
检查 static void read3()抛出IOException {
// read from the file with buffering
// and with direct access to the buffer
MyTimer mt = new MyTimer();
FileInputStream fis =
new FileInputStream(TESTFILE);
cnt3 = 0;
final int BUFSIZE = 1024;
byte buf[] = new byte[BUFSIZE];
int len;
while ((len = fis.read(buf)) != -1) {
for (int i = 0; i < len; i++) {
if (buf[i] == 'A') {
cnt3++;
}
}
}
fis.close();
System.out.println("read3 time = "
+ mt.getElapsed());
}
来自http://java.sun.com/developer/JDCTechTips/2002/tt0305.html
最佳缓冲区大小可能取决于操作系统。 你的可能很小。