Многие небольшие файлы или один большой файл? (Или, накладные расходы на открытие и закрытие файлов) (С++)

Я создал приложение, которое выполняет следующие действия:

  • Сделайте несколько вычислений, напишите рассчитанные данные в файл - повторите 500 000 раз (над всем, напишите 500 000 файлов один за другим) - повторите еще 2 раза (по всему, 1,5 миллиона файлов были написано).
  • Прочитайте данные из файла, сделайте некоторые интенсивные вычисления с данными из файла - повторите для 1 500 000 итераций (повторите все файлы, написанные на шаге 1.)
  • Повторите шаг 2 для 200 итераций.

Каждый файл ~ 212k, поэтому у меня есть ~ 300Gb данных. Похоже, что весь процесс занимает ~ 40 дней на процессоре Core 2 Duo с 2,8 ГГц.

Моя проблема (как вы можете догадаться) - это время, необходимое для завершения всего процесса. Все вычисления являются серийными (каждый расчет зависит от предыдущего), поэтому я не могу параллельно выполнять этот процесс для разных ЦП или ПК. Я пытаюсь думать, как сделать процесс более эффективным, и я уверен, что большая часть накладных расходов идет на доступ к файловой системе (duh...). Каждый раз, когда я обращаюсь к файлу, я открываю ему дескриптор, а затем закрываю его, когда закончу чтение данных.

Одна из моих идей по улучшению времени выполнения заключалась в том, чтобы использовать один большой файл размером 300 Гбит (или несколько больших файлов по 50 Гб каждый), а затем я бы использовал только один дескриптор открытого файла и просто искал каждую соответствующую информацию и читал ее, но я не то, что накладные расходы на открытие и закрытие дескрипторов файлов. может кто-то пролить свет на это?

Еще одна идея, которую я имел, заключалась в том, чтобы попытаться сгруппировать файлы в более крупные файлы размером ~ 100 Мб, а затем я буду читать 100 МБ каждый раз, а не многие 212k-чтения, но это намного сложнее реализовать, чем идея выше.

В любом случае, если кто-нибудь может дать мне несколько советов по этому поводу или у вас есть идея, как улучшить время выполнения, я был бы признателен!

Спасибо.

Обновление профилировщика:

Я запустил профайлер процесса, похоже, что вычисления занимают 62% времени исполнения, а чтение файла занимает 34%. Имея в виду, что даже если я чудесным образом сократил расходы на входы/выходы файла в 34 раза, я все еще остаюсь на 24 дня, что является довольно хорошим улучшением, но все еще долгое время:)

Ответ 1

Открытие дескриптора файла не является узким местом; фактический диск IO. Если вы можете распараллеливать доступ к диску (например, используя несколько дисков, более быстрые диски, RAM-диск,...), вы можете выиграть больше. Кроме того, убедитесь, что IO не блокирует приложение: читайте с диска и выполняйте процесс, ожидая ввода-вывода. Например. с считывателем и потоком процессора.

Другое дело: если следующий шаг зависит от текущего расчета, зачем нужно пытаться сохранить его на диск? Возможно, с другим представлением о зависимостях процесса вы можете переработать поток данных и избавиться от большого количества ввода-вывода.

О да, и измерьте это:)

Ответ 2

Каждый файл ~ 212k, поэтому все, что у меня есть ~ 300 Гб данных. Похоже, весь процесс занимает ~ 40 дней... расчеты являются серийными (каждый расчет зависит от до), поэтому я не могу параллелировать это процесс для разных процессоров или ПК.... Симпатичная уверен, что большая часть накладных расходов доступ к файловой системе... время я получаю доступ к файлу, я открываю ручку к нему, а затем закройте его, как только я закончу считывая данные.

Запись данных 300 ГБ данных может занять 40 минут, всего лишь 40%. Производительность записи на диск не должна быть проблемой.

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

Моя ставка - самая быстрая реализация этого приложения, будет использовать файл с отображением памяти, все современные операционные системы имеют эту возможность. В конце концов, это тоже самый простой код. Вам понадобится 64-разрядный процессор и операционная система, вам не потребуется 300 ГБ оперативной памяти. Сопоставьте весь файл в адресное пространство за один раз и просто прочитайте и напишите свои данные с помощью указателей.

Ответ 3

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

Ответ 4

Как насчет использования SQLite? Я думаю, вы можете уйти с одной таблицей.

Ответ 5

Из вашего краткого объяснения это звучит как предложение xtofl потоков - правильный путь. Я бы порекомендовал вам сначала профилировать ваше приложение, но для того, чтобы время делилось между IO процессором.

Тогда я бы рассмотрел три потока, соединенных двумя очередями.

  • Thread 1 читает файлы и загружает их в ram, а затем помещает данные/указатели в очередь. Если очередь занимает определенный размер, поток спит, если он заходит ниже определенного размера, если он начинается снова.
  • В потоке 2 считываются данные из очереди, и затем вычисления затем записывают данные во вторую очередь
  • Тема 3 читает вторую очередь и записывает данные на диск

Вы можете рассмотреть вопрос о слиянии потоков 1 и 3, это может уменьшить количество конфликтов на диске, так как ваше приложение будет делать только один диск за раз.

Также как операционная система обрабатывает все файлы? Все ли они в одном каталоге? Что такое производительность, как при просмотре каталога (gui filemanager/dir/ls)? Если эта производительность плохая, вы можете работать вне зоны комфорта файловых систем. Хотя вы можете изменить это только в unix, некоторые файловые системы оптимизированы для разных типов использования файлов, например, больших файлов, большого количества небольших файлов и т.д. Вы также можете рассмотреть возможность разделения файлов на разные каталоги.

Ответ 6

Использование сопоставленных файлов памяти должно быть исследовано, так как это уменьшит количество системных вызовов.