5

为了尝试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;
}

我在一个大约 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。

4

1 回答 1

10

代码很慢,因为fc.size()是在循环中调用的。

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

将此更改为

    long size = fc.size();
    for (long i = 0; i < size; i++) {
        ...
    }
于 2016-04-02T13:28:32.540 回答