Почему эта программа "подсчета строк" ​​работает медленно в Java? Использование MappedByteBuffer

Пытаться MappedByteBuffer (файл отображен в памяти на Java), я написал простой wc -l (количество строк в текстовом файле) demo:

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 МБ (15008641 байт) и 100 тыс. Строк. На моем ноутбуке это занимает около 13.8 sec, Почему это так медленно?

Полный код класса здесь: http://pastebin.com/t8PLRGMa

Для справки я написал ту же идею в C: http://pastebin.com/hXnDvZm6

Это работает около 28 мс, или 490 times faster,

Из любопытства я также написал версию Scala, использующую, по сути, тот же алгоритм и API, что и в Java. Работает 10 times faster, который предполагает, что определенно происходит что-то странное.

Обновление: файл кэшируется операционной системой, поэтому время загрузки диска не требуется.

Я хотел использовать отображение памяти для произвольного доступа к большим файлам, которые могут не помещаться в ОЗУ. Вот почему я не просто использую BufferedReader.

1 ответ

Решение

Код очень медленный, потому что fc.size() вызывается в цикле.

JVM явно не может устранить fc.size(), так как размер файла может быть изменен во время выполнения. Запрос размера файла является относительно медленным, потому что он требует системного вызова базовой файловой системы.

Изменить это на

    long size = fc.size();
    for (long i = 0; i < size; i++) {
        ...
    }
Другие вопросы по тегам