Рекомендация: частое использование большого временного буфера в функции (C ++) - PullRequest
1 голос
/ 26 сентября 2019

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

В настоящее время я вижу следующие варианты:

  1. распределение / освобождение каждый раз
  2. использование статической переменной для хранения этой памяти в сочетании с общим указателем для обеспечения безопасного уничтожения выделенной памяти
  3. с использованием глобальной (или файловой области) памяти для сохранения памяти, выделенной на все время.
  4. инкапсуляция функции внутри класса и добавление переменной-члена, содержащей выделенную память (здесь я в основном обеспокоен

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

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

Относительно подхода 2 Я снова получил некоторое недоверие: переменная-членмогут быть доступны для всех функций в одном и том же классе, хотя предполагаемая область должна быть только для временного вычисления в пределах этой единственной функции-члена.

Возможно, могут помочь некоторые соглашения об именах для этой переменной, а также комментарии: Например,

...
private:
/** this variable is only intended to be used temporarily within fct1 */
std::shared_ptr<std::array<double, 10000>> tmpBuffer;
...

Ответы [ 2 ]

0 голосов
/ 27 сентября 2019

Предположим, у вас есть функция F, которая хочет использовать большой временный буфер B.

  1. Вы не хотите выделять и освобождать B каждый разF вызывается, если F вызывается с высокой частотой.

  2. Я не уверен, что вы имеете в виду в варианте №2.Если B объявлен статическим, то вы не должны / не должны помещать его в shared_ptr.Статические переменные имеют время жизни программы, которым умные указатели не могут / не должны управлять.

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

  4. Вы можете инкапсулировать B внутри класса C, сконструироватьэкземпляр S и передать ссылку S в качестве аргумента F.Другие функции не смогут получить доступ к B, если вы не передадите им S.

По моему мнению, из вышеуказанных 4 опций вы не хотитевыполните # 1 по соображениям производительности, # 2 лучше, чем # 3 для более узкой видимости, и # 4 кажется наиболее гибким.

Используя атомарные операции в средствах доступа B в # 4, вы также можетеразрешить нескольким потокам вызывать функцию одновременно, предоставляя доступ к B.Или вы можете просто использовать разные экземпляры C в потоках, которые не должны использовать один и тот же буфер.Также не имеет значения, является ли F статической функцией метода-члена класса;поведения одинаковы.

Недостатком является то, что F теперь требует дополнительный параметр (C& s), чья продолжительность жизни должна управляться вашей программой за пределами F.Но это по сути то, что вы хотите - для оптимизации производительности.

0 голосов
/ 26 сентября 2019

Ваш подход в «слегка измененном» вопросе кажется оправданным.Если у вас есть функция, многократно работающая с каким-либо фрагментом данных, которая используется в некоторых других областях ограниченным образом, но не предназначена для доступа ко всей программе, это может быть признаком того, что эти данные и эти функции должны быть связаны вместе какчлены и методы в одном классе.Как только этот класс определен, время жизни его экземпляров может быть обработано более просто с помощью обычных средств, таких как scoping, std::shared_ptr или аналогичных.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...