Оптимизация открытия и чтения файлов

У меня есть приложение C++, работающее в Windows, которое просыпается каждые 15 минут, чтобы открывать и читать файлы, находящиеся в каталоге. Каталог меняется при каждом запуске.

  • open выполняется с помощью ifstream.open(file_name, std::ios::binary)
  • чтение выполняется с помощью streambuf ios::rdbuf()*
  • Общее количество файлов каждые 15 минут составляет около 50 000
  • Файлы открываются и считываются партиями по 20 штук.
  • Размер каждого файла составляет около 50 Кбайт.

За каждый прогон; эта операция (открытие и чтение) занимает около 18-23 минут на двухъядерном компьютере со скоростью вращения диска 6000 об/мин. Я зафиксировал ошибку страницы памяти в секунду, и они находятся в диапазоне 8000–10000.

Есть ли способ уменьшить количество ошибок страниц и оптимизировать операцию открытия и чтения файлов?

Гоутэм


person Community    schedule 10.07.2009    source источник
comment
Вы не говорите, как вы читаете из rdbuf. Если вы не читаете весь файл за один вызов, попробуйте установить буфер в rdbuf на размер файла. Это очень простое изменение кода, поэтому стоит поэкспериментировать, и оно может очень помочь. Если код в настоящее время читает 20 файлов одновременно небольшими порциями по несколько КБ, то диск может выполнять до одного поиска на порцию. Таким образом, больший буфер => большие фрагменты => меньше операций поиска => быстрее. С надеждой. Конечно, это может не иметь никакого значения, поскольку Windows может уже спекулятивно кэшировать весь файл.   -  person Steve Jessop    schedule 10.07.2009


Ответы (4)


Не используйте STL, если этого можно избежать. Он справляется с очень сложными проблемами интернационализации и перевода/преобразования, что делает его медленным.

Чаще всего самый быстрый способ прочитать файл — это отобразить его в память (также в Windows, CreateFileMapping в качестве отправной точки. Если возможно, используйте один файл с общим размером 50 000*50 КБ и напрямую индексируйте этот файл при записи/чтении. Вам также следует рассмотреть возможность использования БД (даже SQLite), если данные вообще структурированы. Этот объем данных настолько мал, что должен постоянно оставаться в памяти. Вы также можете попробовать использовать виртуальный диск, чтобы вообще не обращаться к диску (это потребует восстановления после ошибок в в случае сбоя оборудования/электричества).

person Pasi Savolainen    schedule 10.07.2009
comment
Он справляется с очень сложными проблемами интернационализации и перевода/преобразования, что делает его медленным. Это полностью зависит от реализации. Если вы выполняете операции чтения на уровне streambuf, тогда не должно быть проблем с форматированием i18n, и для реализации вполне разумно (даже предпочтительно) не выполнять и кодировать преобразования, передавая байты, хранящиеся на диске. - person CB Bailey; 10.07.2009
comment
На двухъядерной машине с диском на 6000 об/мин я был бы немного удивлен, если бы у него было 2,5 ГБ ОЗУ для RAM-диска. Но это, безусловно, ускорило бы дело, если бы он это сделал. - person Steve Jessop; 10.07.2009

Первый; Спасибо за ответы на все вопросы. Это было очень полезно и предоставило нам множество возможностей для изучения.

Мы удалили STL и использовали C (fopen и fread). Это дало нам небольшое улучшение: операция Open & Read для вышеупомянутых данных заняла 16–17 минут.

Мы действительно решили проблему, сжав эти файлы. Это уменьшило размер каждого файла с 50 КБ до 8 КБ. Время, затрачиваемое на операцию открытия и чтения, сократилось до 4–5 минут.

Спасибо.

person Community    schedule 17.07.2009

Согласно документации MS PSDK, может использоваться кэширование файлов. И, ИМХО, вместо STL, встроенные в Windows CreatFile, ReadFile и CloseHandle с соответствующими флагами могут повысить производительность, поскольку вы упомянули окна.

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

person noel aye    schedule 10.07.2009

  1. Возможно, вы можете использовать что-то вроде мемоизации, т.е. если файл не изменился (вы можете сохранить время его последнего обновления), то вы можете использовать его с последнего раза, т.е. вместо этого сохранить что-то в памяти.

  2. Я думаю, вам не нужно кэширование FS. т.е. будет лучше открывать файлы в режиме O_DIRECT (это linux, но я уверен, что в Windows есть что-то подобное) и читать каждый файл за один ввод-вывод, т.е. создавать буфер в памяти размера файла и читать в него. Это должно значительно снизить использование ЦП и памяти.

  3. Многопоточность, предложенная выше, тоже поможет, но не сильно. Я подозреваю, что узким местом является диск, который может выполнять ограниченное количество операций ввода-вывода в секунду (оценка может составлять 100). Вот почему вам нужно уменьшить количество операций ввода-вывода, например, используя (1), (2), описанные выше, или что-то еще.

person Drakosha    schedule 10.07.2009