Структуры по сравнению с классами

Я собираюсь создать 100 000 объектов в коде. Они небольшие, только с 2 или 3 свойствами. Я положу их в общий список, и когда они будут, я зациклю их и проведу значение a и, возможно, обновить значение b.

Быстрее/лучше создавать эти объекты как класс или как struct?

ИЗМЕНИТЬ

а. Свойства - это типы значений (за исключением строки, которую я думаю?)

б. Они могут (мы еще не уверены) иметь метод проверки достоверности

РЕДАКТИРОВАТЬ 2

Мне было интересно: есть объекты в куче и стек, обработанные одинаково сборщиком мусора, или это работает иначе?

Ответ 1

Является ли быстрее создавать эти объекты как класс или как struct?

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

Структуры потребляют меньше памяти кучи (потому что они меньше и легче уплотняются, а не потому, что они "находятся в стеке" ). Но они копируют больше, чем копия. Я не знаю, каковы ваши показатели производительности для использования памяти или скорости; там есть компромисс, и вы тот, кто знает, что это такое.

Является ли лучше создавать эти объекты как класс или как struct?

Может быть, класс, возможно, структура. Как правило большого пальца: Если объект:
1. Малый
2. Логически непреложное значение
3. Там их много. Тогда я бы подумал о создании структуры. В противном случае я бы придерживался ссылочного типа.

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

Являются ли объекты в куче и стеке одинаково обработаны сборщиком мусора?

Нет, они не совпадают, поскольку объекты в стеке являются корнями коллекции. Сборщику мусора не нужно когда-либо спрашивать: "Это живая вещь в стеке?" потому что ответ на этот вопрос всегда "Да, это в стеке". (Теперь вы не можете полагаться на это, чтобы сохранить объект живым, потому что стек является деталью реализации. Джиттеру разрешено вводить оптимизацию, которая, скажем, регистрирует то, что обычно является значением стека, а затем никогда в стеке поэтому GC не знает, что он все еще жив. Зарегистрированный объект может собирать своих потомков агрессивно, как только регистр, удерживаемый на нем, не будет снова прочитан.)

Но сборщик мусора должен рассматривать объекты в стеке как живые, так же, как он относится к любому объекту, который, как известно, жив как живой. Объект в стеке может ссылаться на объекты, выделенные кучей, которые необходимо сохранить в живых, поэтому GC должен обрабатывать объекты стека, такие как живые объекты, выделенные кучей, для определения живого набора. Но, очевидно, они не рассматриваются как "живые объекты" для уплотнения кучи, потому что они не находятся в куче в первую очередь.

Это ясно?

Ответ 2

Иногда с struct вам не нужно вызывать конструктор new() и напрямую назначать поля, делающие его намного быстрее обычного.

Пример:

Value[] list = new Value[N];
for (int i = 0; i < N; i++)
{
    list[i].id = i;
    list[i].is_valid = true;
}

примерно в 2 - 3 раза быстрее, чем

Value[] list = new Value[N];
for (int i = 0; i < N; i++)
{
    list[i] = new Value(i, true);
}

где Value - это struct с двумя полями (id и is_valid).

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

Ответ 3

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

Поэтому лучше использовать классы.

Связанное чтение: Почему изменчивые структуры "злые" ?

Ответ 4

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

Когда вы вызываете оператор New в классе, он будет выделен в куче. Однако при создании экземпляра структуры он создается в стеке. Это даст прирост производительности. Кроме того, вы не будете иметь дело со ссылками на экземпляр структуры, как с классами. Вы будете работать непосредственно со экземпляром struct. Из-за этого при передаче структуры методу она передается по значению, а не как ссылка.

Подробнее здесь:

http://msdn.microsoft.com/en-us/library/aa288471(VS.71).aspx

Ответ 5

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

В этом случае, когда вы помещаете их в List<> (а a List<> поддерживается на массив), было бы более эффективно использовать память в памяти.

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

Ответ 6

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

Как и во втором редактировании, GC имеет дело только с кучей, но есть намного больше места для кучи, чем пространство стека, поэтому размещение вещей в стеке не всегда является победой. Кроме того, список типов struct и список типов классов будет в куче в любом случае, поэтому в этом случае это не имеет значения.

Edit:

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

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

В самом деле, я думаю, что "он мутирует, так что это плохой показатель" не намного лучше, чем о куче и стеке (что, по крайней мере, имеет некоторое влияние на производительность, даже если оно часто искажается). "Он мутирует, поэтому он вполне вероятен не имеет смысла считать его имеющим семантику значений, поэтому она плохой структурой" немного отличается, но, что важно, я думаю.

Ответ 7

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

Ответ 8

Структура в своем сердце - не что иное, как агрегация полей. В .NET возможно, что структура "притворяется" объектом, а для каждого типа структуры .NET неявно определяет тип объекта кучи с теми же полями и методами, которые - будучи объектом кучи - будут вести себя как объект, Переменная, которая содержит ссылку на такой объект кучи ( "в штучной упаковке" ), будет демонстрировать ссылочную семантику, но тот, который непосредственно содержит структуру, представляет собой просто агрегацию переменных.

Я думаю, что большая часть беспорядка между структурами и классами проистекает из того факта, что структуры имеют два очень разных случая использования, которые должны иметь очень разные принципы проектирования, но рекомендации MS не различают их. Иногда возникает потребность в том, что ведет себя как объект; в этом случае рекомендации MS довольно разумны, хотя "ограничение по 16 байт" должно быть больше похоже на 24-32. Иногда, однако, необходимо агрегирование переменных. Строка, используемая для этой цели, должна состоять только из совокупности открытых полей и, возможно, переопределения Equals, ToString и IEquatable(itsType).Equals. Структуры, которые используются как скопления полей, не являются объектами и не должны претендовать на роль. С точки зрения структуры, значение поля должно быть не более или менее, чем "последнее, что написано в этом поле". Любое дополнительное значение должно определяться кодом клиента.

Например, если переменная-агрегационная структура имеет члены Minimum и Maximum, сама структура не должна обещать, что Minimum <= Maximum. Код, который получает такую ​​структуру как параметр, должен вести себя так, как если бы он передавался отдельным значениям Minimum и Maximum. Требование о том, чтобы Minimum не превышало Maximum, должно рассматриваться как требование, чтобы параметр Minimum не превышал отдельно переданный Maximum.

Полезным примером для рассмотрения иногда является наличие класса ExposedHolder<T>, определенного как:

class ExposedHolder<T>
{
  public T Value;
  ExposedHolder() { }
  ExposedHolder(T val) { Value = T; }
}

Если у меня есть List<ExposedHolder<someStruct>>, где someStruct представляет собой структуру, агрегирующую переменную, можно делать такие вещи, как myList[3].Value.someField += 7;, но предоставление myList[3].Value другому коду даст ему содержимое Value, а не давая ему возможность изменить его. В отличие от этого, если использовать a List<someStruct>, необходимо использовать var temp=myList[3]; temp.someField += 7; myList[3] = temp;. Если вы использовали тип изменяемого класса, подвергая содержимое myList[3] внешнему коду, потребуется скопировать все поля в какой-либо другой объект. Если бы использовался тип неизменяемого класса или структура типа "объект-стиль", необходимо было бы создать новый экземпляр, который был как myList[3], за исключением someField, который был другим, а затем сохранил этот новый экземпляр в списке.

Еще одно примечание. Если вы храните большое количество похожих вещей, может быть полезно сохранить их в возможно-вложенных массивах структур, предпочтительно, чтобы сохранить размер каждого массива между 1K и 64K или около того. Массивы структур являются особенными, поскольку индексирование дает прямую ссылку на структуру внутри, поэтому можно сказать "a [12].x = 5;". Хотя можно определить объекты типа массива, С# не позволяет им использовать такой синтаксис с массивами.

Ответ 9

С точки зрения С++ я согласен, что это будет медленнее изменять свойства structs по сравнению с классом. Но я думаю, что они будут быстрее читать из-за того, что структура выделяется в стеке вместо кучи. Чтение данных из кучи требует больше проверок, чем из стека.

Ответ 10

Использовать классы.

Об общем примечании. Почему бы не обновить значение b при их создании?

Ответ 11

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

Это повторение: производительность.