- Выделение кучи действительно довольно дорогое.
- преждевременная оптимизация плохая, но если ваша библиотека довольно общая, а матрицы огромны, возможно, преждевременно искать эффективный дизайн. В конце концов, вы не хотите изменять свой дизайн после того, как вы накопили много зависимостей.
- Существуют различные уровни, на которых вы можете решить эту проблему. Например, вы можете избежать затрат на распределение кучи, выполнив его на уровне распределителя памяти (например, в пуле памяти с потоком)
- , а выделение кучи дорого, вы создаете одну гигантскую матрицу только для выполнения довольно дорогостоящих операций на матрицах (обычно линейная сложность или хуже). Сравнительно говоря, выделение матрицы в свободном хранилище может быть не столь дорогостоящим по сравнению с тем, что вы неизбежно будете иметь с этим делать впоследствии, поэтому оно может быть довольно дешевым по сравнению с общей логикой функции, такой как сортировка.
Я рекомендую вам написать код, естественно, принимая во внимание № 3 в качестве будущей возможности. То есть, не принимайте ссылки на матричные буферы для промежуточных вычислений, чтобы ускорить создание временных рядов. Сделайте временные значения и верните их по значению. На первом месте правильность и хорошие, понятные интерфейсы.
Главным образом цель здесь состоит в том, чтобы отделить стратегию создания матрицы (через распределитель или другие средства), которая дает вам эту комнату для отдыха, чтобы оптимизировать как запоздалую мысль, не меняя слишком много существующего кода. Если вы можете сделать это, изменив только детали реализации задействованных функций или, еще лучше, изменив только реализацию вашего матричного класса, тогда вы действительно здоровы, потому что тогда вы можете оптимизировать без изменения дизайна и любой дизайн, который позволяет, как правило, быть полным с точки зрения эффективности.
ПРЕДУПРЕЖДЕНИЕ. Следующее предназначено только в том случае, если вы действительно хотите выжать максимум из каждого цикла. Важно понимать №4, а также получить хороший профилировщик. Также стоит отметить, что вы, вероятно, сделаете лучше, оптимизируя шаблоны доступа к памяти для этих матричных алгоритмов, чем пытаетесь оптимизировать распределение кучи.
Если вам нужно оптимизировать выделение памяти, подумайте об оптимизации его с чем-то общим, как пул памяти в потоках. Например, вы можете сделать свою матрицу в необязательном распределителе, но я подчеркиваю необязательный вариант, и я также хотел бы подчеркнуть правильность сначала с помощью тривиальной реализации распределителя.
Другими словами:
Это лучше практика, чтобы объявить M1 (п, р) в пределах каждой функции, или , а раз и навсегда, в основном() и передать его в каждой функции в качестве своего рода ведро, которое каждая функция может использовать как пространство для лома.
Вперед и создайте M1 как временное в каждой функции. Старайтесь не требовать от клиента создания какой-либо матрицы, которая не имеет для него значения, только для вычисления промежуточных результатов. Это будет раскрывать детали оптимизации, которые мы должны стремиться не делать при разработке интерфейсов (скрыть все детали, о которых клиенты не должны знать).
Вместо этого сосредоточьтесь на более общих понятиях, если вы абсолютно хотите, чтобы эта опция ускорила создание этих временных рядов, например, дополнительный распределитель. Это согласуется с практическим дизайном, как с std::set
:
std::set<int, std::less<int>, MyFastAllocator<int>> s; // <-- okay
Несмотря на то, что большинство людей просто сделать:
std::set<int> s;
В вашем случае это может быть просто: M1 my_matrix (п, р, Alloc) ;
Это тонкая разница, но распределитель является гораздо более общей концепцией, которую мы можем использовать, чем кешированная матрица, которая в противном случае не имеет никакого смысла для клиента, за исключением того, что это какой-то кеш, который требуется вашим функциям, чтобы помочь им быстрее вычислять результаты , Обратите внимание, что он не должен быть общим распределителем. Это может быть только ваш предварительно выделенный матричный буфер, переданный матричному конструктору, но концептуально было бы полезно разделить его просто на то, что это нечто более непрозрачное для клиентов.
Кроме того, для создания этого временного матричного объекта также потребуется не делиться им по потокам. Это еще одна причина, по которой вы, вероятно, хотите немного обобщить концепцию, если вы идете по пути оптимизации, поскольку нечто более общее, например, матричный распределитель, может учитывать проблему безопасности потоков или, по крайней мере, подчеркивать больше по дизайну, что отдельный распределитель должен создаваться в потоке, но исходный объект-матрица, вероятно, не может.
Приведенное выше полезно, только если вы действительно заботитесь о качестве своих интерфейсов в первую очередь. Если нет, я бы посоветовал обратиться к совету Маттиу, поскольку он намного проще, чем создание распределителя, но оба из нас подчеркивают необходимость ускорения версии .
зависит. Распределение памяти дорого. начните с локальных распределений и измените, если allocs являются слишком дорогостоящими. – Anycorn
@ Распределение памяти из Aycycorn, вероятно, менее дорогое, чем доступ к 500 или более значениям, и, безусловно, менее дорогостоящий, чем доступ к миллионам значений. –
@JamesKanze +1 относительная эффективность распределения кучи обычно будет тривиальной по сравнению с этими операциями. Я подумываю о редактировании сообщения, чтобы полностью не предлагать маршрут оптимизации. – stinky472