为什么这个"行数"程序在Java中变慢?使用MappedByteBuffer

cid*_*ole 5 java performance nio mappedbytebuffer

为了尝试MappedByteBuffer(Java中的内存映射文件),我编写了一个简单的wc -l(文本文件行计数)演示:

int wordCount(String fileName) throws IOException {
    FileChannel fc = new RandomAccessFile(new File(fileName), "r").getChannel();
    MappedByteBuffer mem = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());

    int nlines = 0;
    byte newline = '\n';

    for(long i = 0; i < fc.size(); i++) {
        if(mem.get() == newline)
            nlines += 1;
    }

    return nlines;
}
Run Code Online (Sandbox Code Playgroud)

我在大约15 MB(15008641字节)和100k行的文件上尝试了这个.在我的笔记本电脑上,它需要13.8 sec.为什么这么慢?

完整的类代码在这里:http://pastebin.com/t8PLRGMa

作为参考,我在C中写了相同的想法:http://pastebin.com/hXnDvZm6

它运行大约28毫秒,或490 times faster.

出于好奇,我还使用与Java中基本相同的算法和API编写了Scala版本.它运行10 times faster,这表明肯定有一些奇怪的事情发生.

更新:该文件由操作系统缓存,因此不会涉及磁盘加载时间.

我想使用内存映射来随机访问可能不适合RAM的较大文件.这就是为什么我不只是使用BufferedReader.

apa*_*gin 10

代码非常慢,因为fc.size()在循环中调用.

JVM显然无法消除fc.size(),因为文件大小可以在运行时更改.查询文件大小相对较慢,因为它需要对底层文件系统进行系统调用.

将此更改为

    long size = fc.size();
    for (long i = 0; i < size; i++) {
        ...
    }
Run Code Online (Sandbox Code Playgroud)