С против.C++ для повышения производительности при распределении памяти

StackOverflow https://stackoverflow.com/questions/2513741

Вопрос

Я планирую участвовать в разработке кода, написанного на языке C для анализа сложных задач методом Монте-Карло.Этот код размещает в памяти огромные массивы данных для ускорения своей работы, поэтому автор кода выбрал C вместо C++, утверждая, что на C можно сделать более быстрый и надежный (относительно утечек памяти) код.

Согласны ли вы с этим?Каким будет ваш выбор, если во время вычислений вам потребуется хранить в памяти 4–16 ГБ массивов данных?

Это было полезно?

Решение

Определенно С++.По умолчанию между ними нет существенной разницы, но C++ предоставляет несколько вещей, которых нет в C:

  1. конструкторы/деструкторы.Они позволяют автоматизировать большую часть управления памятью, повышая надежность.
  2. распределители для каждого класса.Они позволяют оптимизировать распределение в зависимости от того, как разрабатываются и/или используются конкретные объекты.Это может быть особенно полезно, если вам нужно большое количество мелких объектов (приведу один очевидный пример).

Суть в том, что в этом отношении C не дает абсолютно никаких преимуществ перед C++.В самом худшем случае вы можете делать то же самое и теми же способами.

Другие советы

Есть одна особенность C99, которая отсутствует в C++ и которая потенциально дает значительный прирост скорости в тяжелом коде обработки чисел, и это ключевое слово restrict.Если вы можете использовать компилятор C++, который его поддерживает, то у вас в комплекте есть дополнительный инструмент для оптимизации.Однако это всего лишь потенциальная выгода:достаточная встраивание может обеспечить ту же оптимизацию, что и restrict и более.Это также не имеет никакого отношения к распределению памяти.

Если автор кода может продемонстрировать разницу в производительности между кодом C и C++, выделяющим массив размером 4–16 ГБ, то (а) я удивлён, но ок, разница есть, и (б) сколько раз собирается ли программа выделять такие большие массивы?Действительно ли ваша программа будет тратить значительное количество времени на выделение памяти, или она тратит большую часть своего времени доступ память и выполнение вычислений?На самом деле нужно много времени делать что-либо с массивом размером 4 ГБ по сравнению со временем, необходимым для выделения, а это означает, что вам следует беспокоиться о производительности «чего-либо», а не о производительности распределения.Спринтеров очень волнует, как быстро они отрываются от блоков.Марафонцы, не так уж и много.

Вы также должны быть осторожны при проведении бенчмаркинга.Вы должны сравнивать, например malloc(size) против new char[size].Если вы тестируете malloc(size) против new char[size]() тогда это несправедливое сравнение, поскольку последний устанавливает память в 0, а первый — нет.Сравните с calloc вместо этого, но также обратите внимание, что malloc и calloc оба доступны из C++ в том (маловероятном) случае, что они окажутся заметно быстрее.

В конечном счете, однако, если автор «владеет» проектом или начал его и предпочитает писать на C, а не на C++, тогда он не должен оправдывать свое решение вероятно ложными заявлениями о производительности, он должен оправдать его, сказав: «Я предпочитаю C». , и это то, что я использую».Обычно, когда кто-то делает такое заявление о языковых характеристиках, а тестирование оказывается неверным, вы обнаруживаете, что производительность не является реальной причиной языковых предпочтений.Доказательство ложности утверждения на самом деле не приведет к тому, что автор этого проекта внезапно полюбит C++.

Реальной разницы между C и C++ с точки зрения распределения памяти нет.C++ имеет больше «скрытых» данных, таких как виртуальные указатели и т. д., если вы решили использовать виртуальные методы для своих объектов.Но выделение массива символов в C столь же затратно, как и в C++, более того, они, вероятно, оба используют для этого malloc.С точки зрения производительности C++ вызывает конструктор для каждого объекта массива.Обратите внимание, что это делается только в том случае, если он есть, конструктор по умолчанию ничего не делает и оптимизируется.

Пока вы предварительно выделяете пулы данных, чтобы избежать фрагментации памяти, все будет в порядке.Если у вас есть простые POD-структуры без виртуальных методов и без конструкторов, разницы нет.

Единственное, что не в пользу C++, — это его дополнительная сложность. — совместите это с программистом, который его неправильно использует, и вы легко сможете заметно тормозить.Использование компилятора C++ без функций C++ обеспечит такую ​​же производительность.Правильно используя C++, у вас есть некоторые возможности стать быстрее.

Язык — не твоя проблема, выделение и перемещение больших массивов.

Основная смертельная ошибка, которую вы можете совершить при распределении (на любом языке), — это выделение 16 ГБ памяти, инициализация ее нулевым значением только для того, чтобы позже заполнить ее фактическими значениями.

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

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

При распределении необработанных данных не должно быть разницы между C и C++ в большинстве систем, поскольку они обычно используют одни и те же механизмы библиотеки времени выполнения.Интересно, была ли это классическая ошибка в тестировании, когда они также измеряли время выполнения вызовов конструктора в C++ и удобно забыли включить время выполнения любого кода инициализации в C.

Кроме того, аргумент «более надежный (относительно утечек памяти)» не выдерживает никакой критики, если вы используете RAII в C++ (как и должно быть).Если только кто-то не говорит о повышении надежности утечки, использование RAII, интеллектуальных указателей и классов контейнеров уменьшит вероятность утечек, а не увеличит ее.

Мои основные проблемы с выделением такого большого количества памяти могут быть двоякими:

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

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

Вы также можете использовать семейство функций распределения памяти C в C++:оба стандартные malloc и free, realloc увеличивать/сжимать массивы и alloca для выделения памяти в стеке.

Если вы пойдете с new, он выделит больше памяти, чем необходимо (в основном во время отладки) и выполнит дополнительные проверки на согласованность.Он также вызовет конструктор классов.В выпуске (-O3) build разница будет незначительной для большинства приложений.

Что теперь new приносит то, что malloc не находится на месте new.Вы можете предварительно выделить буфер, а затем использовать его на месте. new поместить вашу структуру в этот буфер, тем самым сделав ее «выделение» мгновенным.

В общем, я бы не остался в стороне от C из-за проблем с производительностью.Во всяком случае, ваш код будет более эффективным, потому что классы передают this указатель в регистрах вместо параметров, как в эквиваленте C.Реальная причина держаться подальше от C — это размер среды выполнения C++.Если вы разрабатываете программы для встраиваемых систем или загружаемые при загрузке программы, вы не можете встроить среду выполнения размером ~4 МБ.Однако для обычных приложений это не будет иметь значения.

Если во время вычислений вам необходимо хранить в памяти 4-16 ГБ массивов данных, а физической памяти у вашей машины всего 2 ГБ, то что?

Что делать, если на вашем компьютере 16 ГБ физической памяти?Операционная система не занимает физическую память?

Предоставляет ли операционная система адресное пространство размером 4 ГБ, 16 ГБ и т. д.?

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top