Я собираюсь создать в коде 100 000 объектов. Они маленькие, всего 2 или 3 объекта. Я помещаю их в общий список, а когда они есть, я зацикливаю их, проверяю значение a
и, возможно, обновляю значение b
.
Быстрее / лучше создавать эти объекты как класс или как структуру?
РЕДАКТИРОВАТЬ
а. Свойства являются типами значений (кроме строки, как мне кажется?)
б. Они могут (мы еще не уверены) иметь метод проверки
РЕДАКТИРОВАТЬ 2
Мне было интересно: объекты в куче и стеке обрабатываются сборщиком мусора одинаково или это работает по-разному?
Ответы:
Вы единственный человек, который может определить ответ на этот вопрос. Попробуйте оба способа, измерьте значимую, ориентированную на пользователя и релевантную метрику производительности, и тогда вы узнаете, оказывает ли изменение значимое влияние на реальных пользователей в соответствующих сценариях.
Структуры потребляют меньше памяти кучи (потому что они меньше и легче сжимаются, а не потому, что они «в стеке»). Но их копирование занимает больше времени, чем эталонный экземпляр. Я не знаю, каковы ваши показатели производительности для использования памяти или скорости; здесь есть компромисс, и вы тот человек, который знает, что это такое.
Может быть, класс, может быть, структура. Практическое правило: если объект:
1. Маленький
2. Логически неизменное значение
3. Их много,
тогда я бы подумал о том, чтобы сделать его структурой. В противном случае я бы остановился на ссылочном типе.
Если вам нужно изменить какое-либо поле структуры, обычно лучше создать конструктор, который возвращает целую новую структуру с правильно установленным полем. Возможно, это немного медленнее (измерьте!), Но логически гораздо легче рассуждать.
Нет , они не совпадают, потому что объекты в стеке являются корнями коллекции . Сборщику мусора даже не нужно спрашивать, «жива ли эта штука в стеке?» потому что ответ на этот вопрос всегда: «Да, это в стеке». (Теперь вы не можете полагаться на это, чтобы поддерживать объект в живых, потому что стек - это деталь реализации. Джиттеру разрешено вводить оптимизацию, которая, скажем, регистрирует то, что обычно было бы значением стека, а затем никогда не в стеке Таким образом, GC не знает, что он все еще жив. Зарегистрированный объект может агрессивно собирать его потомков, как только регистр, хранящий его, больше не будет считываться.)
Но сборщик мусор действительно должен обработать объекты в стеке , как живые, так же, как он относится к какому - либо объекту , известный как живые , как живые. Объект в стеке может относиться к объектам, выделенным в куче, которые необходимо поддерживать в рабочем состоянии, поэтому GC должен обрабатывать объекты стека как живые объекты, выделенные в куче, для целей определения динамического набора. Но очевидно, что они не рассматриваются как «живые объекты» для уплотнения кучи, потому что они вообще не находятся в куче.
Это ясно?
источник
readonly
), чтобы обеспечить оптимизацию. Я бы не позволил этому повлиять на выбор изменчивости (в теории я помешан на деталях эффективности, но на практике мой первый шаг к эффективности всегда пытается получить как можно более простую гарантию правильности и, следовательно, не должен тратить циклы ЦП и мозговые циклы на проверки и крайние случаи, и в этом помогает соответствующая изменчивость или неизменность), но это противодействует любой резкой реакции на ваше высказывание о том, что неизменяемость может быть медленнее.Иногда
struct
вам не нужно вызывать конструктор new () и напрямую назначать поля, что делает его намного быстрее, чем обычно.Пример:
Value[] list = new Value[N]; for (int i = 0; i < N; i++) { list[i].id = i; list[i].isValid = true; }
примерно в 2–3 раза быстрее, чем
Value[] list = new Value[N]; for (int i = 0; i < N; i++) { list[i] = new Value(i, true); }
где
Value
-struct
с двумя полями (id
иisValid
).struct Value { int id; bool isValid; public Value(int i, bool isValid) { this.i = i; this.isValid = isValid; } }
С другой стороны, необходимо перемещать элементы или выбирать типы значений, копирование которых замедлит вас. Чтобы получить точный ответ, я подозреваю, что вам нужно профилировать свой код и протестировать его.
источник
list
, учитывая, что указанный код не будет работать с расширениемList<Value>
.Структуры могут показаться похожими на классы, но есть важные различия, о которых вам следует знать. Прежде всего, классы - это ссылочные типы, а структуры - это типы значений. Используя структуры, вы можете создавать объекты, которые ведут себя как встроенные типы, а также пользоваться их преимуществами.
Когда вы вызываете оператор New для класса, он будет размещен в куче. Однако когда вы создаете экземпляр структуры, она создается в стеке. Это даст прирост производительности. Кроме того, вы не будете иметь дело со ссылками на экземпляр структуры, как с классами. Вы будете работать напрямую с экземпляром структуры. Из-за этого при передаче структуры методу она передается по значению, а не по ссылке.
Подробнее здесь:
http://msdn.microsoft.com/en-us/library/aa288471(VS.71).aspx
источник
Массивы структур представлены в куче в непрерывном блоке памяти, тогда как массив объектов представлен как непрерывный блок ссылок с самими фактическими объектами в другом месте в куче, что требует памяти как для объектов, так и для их ссылок на массивы. .
В этом случае, поскольку вы помещаете их в
List<>
(иList<>
поддерживается массивом), было бы более эффективно с точки зрения памяти использовать структуры.(Помните, что большие массивы попадут в кучу больших объектов, где, если их время жизни велико, может отрицательно повлиять на управление памятью вашего процесса. Помните также, что память - не единственное соображение.)
источник
ref
ключевое слово, чтобы справиться с этим.Если они имеют семантику значений, вам, вероятно, следует использовать структуру. Если они имеют ссылочную семантику, вам, вероятно, следует использовать класс. Есть исключения, которые в основном склоняются к созданию класса даже при наличии семантики значений, но начинают с этого.
Что касается вашего второго редактирования, сборщик мусора имеет дело только с кучей, но места в куче намного больше, чем пространства стека, поэтому размещение вещей в стеке не всегда является победой. Кроме того, список типов структур и список типов классов в любом случае будет в куче, так что в данном случае это не имеет значения.
Редактировать:
Я начинаю считать термин зло вредным. В конце концов, делать класс изменяемым - плохая идея, если в этом нет активной необходимости, и я не исключаю когда-либо использования изменяемой структуры. Это плохая идея так часто, что почти всегда это плохая идея, но в большинстве случаев она просто не совпадает с семантикой значения, поэтому просто не имеет смысла использовать структуру в данном случае.
Могут быть разумные исключения с частными вложенными структурами, где все использования этой структуры, следовательно, ограничены очень ограниченной областью. Однако здесь это не применяется.
На самом деле, я думаю, что «он мутирует, так что это плохой трюк» не намного лучше, чем говорить о куче и стеке (что, по крайней мере, оказывает некоторое влияние на производительность, даже если оно часто искажается). «Он видоизменяется, поэтому, скорее всего , нет смысла рассматривать его как имеющий семантику значений, поэтому это плохая структура» - это лишь немного отличается, но я думаю, что это важно.
источник
Лучшее решение - измерить, снова измерить, а затем измерить еще раз. Могут быть детали того, что вы делаете, что может затруднить упрощенный и легкий ответ, например «использовать структуры» или «использовать классы».
источник
По сути, структура - это не что иное, как совокупность полей. В .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
а не средство для его изменения. Напротив, если бы кто-то использовал aList<someStruct>
, было бы необходимо использоватьvar temp=myList[3]; temp.someField += 7; myList[3] = temp;
. Если бы использовался изменяемый тип класса, для раскрытия содержимогоmyList[3]
внешнего кода потребовалось бы скопировать все поля в какой-либо другой объект. Если бы использовался неизменяемый тип класса или структура «объектного стиля», было бы необходимо построить новый экземпляр, который был бы похож,myList[3]
за исключениемsomeField
который был другим, а затем сохранить этот новый экземпляр в списке.Еще одно замечание: если вы храните большое количество похожих вещей, может быть полезно хранить их в возможно вложенных массивах структур, желательно стараясь сохранить размер каждого массива от 1 до 64 КБ или около того. Массивы структур являются особенными, так как индексирование дает прямую ссылку на структуру внутри, поэтому можно сказать «a [12] .x = 5;». Хотя можно определять объекты, подобные массивам, C # не позволяет им использовать такой синтаксис совместно с массивами.
источник
Используйте классы.
По общему правилу. Почему бы не обновлять значение b по мере их создания?
источник
С точки зрения C ++ я согласен с тем, что изменение свойств структуры будет медленнее по сравнению с классом. Но я думаю, что их будет быстрее читать из-за того, что структура выделяется в стеке, а не в куче. Чтение данных из кучи требует больше проверок, чем из стека.
источник
Что ж, если вы пойдете с struct afterall, то избавьтесь от строки и используйте char или байтовый буфер фиксированного размера.
Это re: производительность.
источник