Эффективное чтение файлов
От: flashnik  
Дата: 07.06.09 22:39
Оценка:
Есть директория, в которой лежит куча файлов (~20000) размера от пары килобайт до 5 мегабайт. Надо их все прочитать и извлечь из них информацию.Формат позволяет разбирать каждую строку в файле независимо от остальных. Как лучше реализовать эту операцию?

  1. Каждый файл считывается в буфер mapBuf размера 8 мегабайт (гарантированно больше размера любого файла)
    ifstr.open(fileName, ios_base::ate);
    if(!ifstr.is_open())
    {
        LOG_ERROR("Unable to open file %s", fileName);
        return false;
    }
    fileSize = ifstr.tellg();
    ifstr.seekg(ios::beg);
    ifstr.read(mapBuf, fileSize);

    и потом парсится содержимое буфера

  2. Файл в несколько заходов считывается в буфер небольшого размера (несколько килобайт) (сколько??)

  3. Файл считывается построчно

  4. файл отображается в память и потом парсится
Какой из этих вариантов будет лучше?
Насколько я понимаю, memory-mapped файлы тут не дадут выигрыша из-за небольшого размера файлов (только 20 % файлов больше 64К).
Re: Эффективное чтение файлов
От: ole! США http://files.rsdn.org/4543/rsdn.gif
Дата: 08.06.09 01:23
Оценка: +1
Здравствуйте, flashnik, Вы писали:

F>Есть директория, в которой лежит куча файлов (~20000) размера от пары килобайт до 5 мегабайт. Надо их все прочитать и извлечь из них информацию.Формат позволяет разбирать каждую строку в файле независимо от остальных. Как лучше реализовать эту операцию?


F>

    F>
  1. Каждый файл считывается в буфер mapBuf размера 8 мегабайт (гарантированно больше размера любого файла)
    F>
    F>ifstr.open(fileName, ios_base::ate);
    F>if(!ifstr.is_open())
    F>{
    F>    LOG_ERROR("Unable to open file %s", fileName);
    F>    return false;
    F>}
    F>fileSize = ifstr.tellg();
    F>ifstr.seekg(ios::beg);
    F>ifstr.read(mapBuf, fileSize);
    F>

    F>и потом парсится содержимое буфера

    F>
  2. Файл в несколько заходов считывается в буфер небольшого размера (несколько килобайт) (сколько??)

    F>
  3. Файл считывается построчно

    F>
  4. файл отображается в память и потом парсится
    F>
F>Какой из этих вариантов будет лучше?
F>Насколько я понимаю, memory-mapped файлы тут не дадут выигрыша из-за небольшого размера файлов (только 20 % файлов больше 64К).

Построчно сичтывать файл смысла большого нет, так что эту опцию можно отбросить сразу.

Отображение файла впамять может дать хороший результат. Файл сразу не считывается, просто память отмечается как зарезервированная, а когда к ней происходит обращение происходит прерывание в ядре (MMU) и ядро догружает недостающие страницы в память (происходит мэппинг). Кстати, загрузить сразу ядро может 64 килобайта, а потом коммитить по 4 килобайта (размер страницы). Это вам известно, не сомневаюсь. В общем случае, что и когда именно делает ядро — неизвестно в user mode. Зато известно, что отображение файлов в память работает хорошо и эффективно во многих случаях.

Парсинг строки, то есть поиск ее конца все равно нужно делать в памяти на уже считанном из файла буфере в памяти. Если конец строки не найден, то нужно досчитать в буфер еще из файла и продолжить поиск. Именно в этом сценарии поможет отображение в память — вся работа с буфером возлагается на ядро — код программы чище, алгоритм — понятнее.

Если вы серьезно затеяли пооптимизировать, то тут можно поиспользовать system specific флаги для работы с файлами. Например, под Windows можно использовать FILE_FLAG_SEQUENTIAL_SCAN
(0x08000000) флаг. Почитать подробнее можно здесь Caching Behavior. Основная идея — передать как можно больше информации ядру о том, как вы собираетесь работать с файлом и что с ним будете делать. Устанавливая только нужные флаги можно отключать ненужную функциональность и помогать файловому кэшу в ядре. В вашем сценарии идет только чтение, переходов по файлу в случайные места не происходит, записи в файл тоже, читаете вы один раз, поэтому оптимально будет отключить кэширование, хотя и не отключать look ahead read оптимизацию чтения. Можно еще также подумать про sharing locks и т.д.

Ну и соответсвенно идаельным ответом будет всегда эксперимент. Просто сделайте несколько вариантов и померяйте производительность, много ли вы выигрываете и в каком случае сколько. Усложняется ли из-за этого алгоритм, код в целом, читаемость и сопровождаемость. Здесь идеального ответа не будет, нужно соблюдать баланс.
my $.02
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.