Я создаю библиотеку геометрии в C#, и мне будут нужны следующие неизменные типы:
Vector2f
(2 float
s - 8 байтов)Vector2d
(2 double
s - 16 байтов)Vector3f
(3 float
s - 12 байтов)Vector3d
(3 double
s - 24 байта)Vector4f
(4 float
s - 16 байтов)Vector4d
(4 double
s - 32 байта)Я пытаюсь определить, сделать ли их структурами или классами. MSDN предлагает только использовать структуру если размер при попытке быть не больше, чем 16 байтов. Та ссылка, кажется, с 2005. 16 байтов являются все еще макс. предложенным размером?
Я уверен что с помощью структур для float
векторы были бы более эффективными, чем использование класса, но что я должен сделать о double
векторы? Я должен сделать их структурами также, чтобы быть последовательным, или я должен сделать их классами?
Обновленный: Похож на всех, соглашается, что они должны быть структурами. Спасибо за большие ответы.
Microsoft XNA Framework использует структуры для своих типов данных Vector2 / 3 / 4 . Они содержат поля типа float
. Я не вижу ничего плохого в том, чтобы делать то же самое; использование полей типа double
не должно иметь большого значения.
Недавно мы переключили некоторые математические типы (vec3, vec4, матрицы и т. Д.) На использование структур вместо классов, и, помимо того, что были немного быстрее в тестах, это также уменьшило нагрузку на сборщик мусора (у нас были сотни мегабайт Vec3 выделения за относительно короткий период времени, обнаруженные с помощью профилировщика CLR).
Интересно отметить, что реализация векторов и матриц Xna выполняется с использованием структур. Вы всегда можете перейти по ссылке, если это необходимо, если вас тоже беспокоит производительность.
Структуры, определенно. Почему? Ну, это отчасти ощущение, я думаю, вектор просто ощущается и ведет себя как значение .
Рико Мариани здесь приводит некоторые причины, по которым типы значений были выбраны для определенных типов для API (я не думаю, что он говорит о XNA).
И хотя здесь решающим фактором является эффективность, я думаю, что дело не в сборке мусора, а в плотности данных , как говорит Рико. Скажем, у вас также есть тип Vertex
, который содержит два Vector3
s: Vector3
для нормального и Vector3
для мирового co. -координаты.Если вы создали классы этих типов, то наличие массива из 100 Vertex
элементов будет состоять из:
Vertex
) вершины
на два элемента Vector3
) Vector3
) float
на Vector3
) 6000 байт (в 32-битной системе).
Как тип значения, это просто 200 * 12 байт = 2400 байт. Гораздо более эффективный с точки зрения пространства, не говоря уже о более низком уровне косвенности при чтении массива.
Но занимание много места не обязательно замедляет его, неправильное использование типа значения может быть медленнее, чем создание класса, как я обнаружил . Вы определенно хотите передать их с помощью ref
в максимально возможной степени, избегайте их копирования, но это не относится к всем операциям, поэтому измерьте. Думаю, я помню, что вычисление скалярного произведения происходило медленнее при прохождении ref
, возможно, потому, что это каким-то образом предотвращало встраивание, увеличивая IL. Но не верьте мне на слово, просто измерьте.
Неизменяемые структуры - хороший выбор. Рекомендуемый размер в MSDN самый слабый, 32 байта - это не очень много.
Основным аргументом было бы то, что векторы используются как простые (числовые) типы и реализация, поскольку тип значения является наиболее подходящим.
Хорошей параллелью являются новые структуры Complex и BigInteger в dotNet 4
На мой взгляд, для этого я бы выбрал структуры, так как в большинстве случаев они будут размещаться в стеке, это снизит нагрузку на сборщик мусора, поэтому ваше приложение должно работать более плавно.
Один совет: ваши методы, которые работают со структурами, вероятно, должны принимать аргументы как аргументы ref и out, это уменьшит объем копирования данных, которое происходит при передаче и возврате структур.
Я бы вообще сделал типы, подобные этим, структурами. Структуры с большей вероятностью будут помещены в стек, и если вы используете с ними массивы, вы можете получить гораздо более приятную производительность, чем, скажем, если бы вы использовали List<> объектов. Пока вы держитесь подальше от операций, которые приведут к тому, что ваши векторные классы окажутся в коробке, struct в целом будет более производительным способом.
Структуры (обычно) хранятся в стеке, что может сделать их более эффективными, но, вероятно, не настолько, чтобы сделать заметную разницу.
Я полагаю, вы беспокоитесь о производительности?
Если они неизменяемы, они должны быть идентичны по поведению. Просто выберите один, а если окажется, что есть проблемы с производительностью, поменяйте его позже.
Если вы вообще нацелены на .NET CE, вам, вероятно, стоит подумать об использовании структур, поскольку GC не так эффективен, как полная реализация .NET.