C malloc / free + производительность fgets - PullRequest
1 голос
/ 12 июня 2009

Когда я перебираю строки в файле A, я анализирую строку и помещаю каждую строку (char*) в char**.

В конце строки я запускаю процедуру, состоящую из открытия файла B, используя fgets, fseek и fgetc для извлечения символов из этого файла. Затем я закрываю файл B.

Я повторяю повторное открытие и повторное закрытие файла B для каждой строки.

Я хотел бы знать следующее:

  1. Есть ли существенное снижение производительности при использовании malloc и free, так что я должен использовать что-то статическое, например myArray[NUM_STRINGS][MAX_STRING_WIDTH] вместо динамического char** myArray?

  2. Существуют ли значительные потери производительности при открытии и закрытии файла B (концептуально, много тысяч раз)? Если мой файл A отсортирован, есть ли способ использовать fseek для перемещения «назад» в файле B, для сброса того места, где я ранее находился в файле B?

РЕДАКТИРОВАТЬ Оказывается, что двойной подход значительно сократил время выполнения:

  1. Мой файл B на самом деле является одним из двадцати четырех файлов. Вместо того, чтобы открыть один и тот же файл B1 тысячу раз, а затем B2 тысячу раз и т. Д. Я открываю файл B1 один раз, закрываю его, B2 один раз, закрываю его и т. Д. Это уменьшает многие тысячи fopen и fclose Операции примерно до 24.

  2. Я использовал rewind() для сброса указателя файла.

Это дало примерно 60-кратное улучшение скорости, что более чем достаточно. Спасибо, что указали мне на rewind().

Ответы [ 8 ]

4 голосов
/ 12 июня 2009

Если ваш динамический массив со временем увеличивается, стоимость копирования составляет около realloc с. Если вы используете эвристику «всегда двойной», она амортизируется до O (n), поэтому она не ужасна. Если вы знаете размер заранее, выделенный массив стека все равно будет быстрее.

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

3 голосов
/ 12 июня 2009

То, что я хотел бы знать, это:

  • Ваш код работает правильно?
  • Это достаточно быстро для вашей цели?

Если ответ на оба вопроса "да", ничего не меняйте.

1 голос
/ 12 июня 2009
  1. Если ваши файлы большие, дисковый ввод-вывод будет намного дороже, чем управление памятью. Беспокойство по поводу производительности malloc / free перед профилированием указывает на то, что это узкое место - преждевременная оптимизация.

  2. Возможно, что издержки от частого открытия / закрытия значительны в вашей программе, но опять же фактический ввод-вывод, вероятно, будет более дорогим, если только файлы не малы, и в этом случае потеря буферов между закрытием и открытием может вызвать дополнительный дисковый ввод-вывод. И да, вы можете использовать ftell (), чтобы получить текущую позицию в файле, затем fseek с SEEK_SET, чтобы добраться до этого.

1 голос
/ 12 июня 2009

Открытие и закрытие имеет переменные издержки в зависимости от того, конкурируют ли другие программы за этот ресурс.

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

Вы не сразу получите многомерный массив, но немного арифметики с указателями, и вы здесь.

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

0 голосов
/ 12 июня 2009

Я часто нахожу, что накладные расходы на производительность перевешиваются прямым управлением памятью, которое поставляется с malloc и этими низкоуровневыми обработчиками C в памяти. Если эти области памяти не будут оставаться статичными и не тронутыми в течение периода времени, который в амортизированном времени больше, чем касание этой памяти, может быть более полезным придерживаться статического массива. В конце концов, решать вам.

0 голосов
/ 12 июня 2009

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

  1. Если вы на самом деле знаете максимальное количество строк и максимальную ширину, это будет намного быстрее (но вы можете тратить много памяти, если используете меньше, чем «max»). Хорошая среда - это делать то, что делают многие реализации динамических массивов в C ++: всякий раз, когда вам нужно перераспределить myArray, выделите вдвое больше места, чем вам нужно, и только снова перераспределяйте, когда у вас закончится пространство. Это имеет O (log n) производительности производительности.

  2. Это может быть большой удар по производительности. Я настоятельно рекомендую использовать fseek, хотя детали будут зависеть от вашего алгоритма.

0 голосов
/ 12 июня 2009
  1. Я думаю, что лучше выделить фактическое пространство, которое вам нужно, и накладных расходов, вероятно, не будет значительное. Это позволяет избежать как Трата пространства и переполнение стека

  2. Да. Хотя IO кешируется, вы делаете ненужные системные вызовы (открыть и закрыть). Используйте fseek с вероятно SEEK_CUR или SEEK_SET.

0 голосов
/ 12 июня 2009

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

Будет также падение производительности при открытии файла. Вы можете использовать fseek (pos, SEEK_SET) для установки указателя файла на любую позицию в файле или fseek (offset, SEEK_CUR) для относительного перемещения.

Значительное снижение производительности относительно, и вам придется определить, что это значит для себя.

...