Я делаю проект хостинга raytracer, и изначально я использовал структуры для объектов Vector и Ray, и я думал, что raytracer - идеальная ситуация для их использования: вы создаете миллионы из них, они не живут дольше чем один метод, они легкие. Однако, просто изменив "struct" на "class" на Vector и Ray, я получил очень значительное увеличение производительности.
Что дает? Они оба маленькие (3 поплавка для вектора, 2 вектора для луча), не копируются чрезмерно. Я, конечно, передаю их методам, но это неизбежно. Итак, каковы общие ошибки, которые убивают производительность при использовании структур? Я прочитал эту статью в MSDN, в которой говорится следующее:
Тем не менее, довольно старый (2001), и целое "помещение их в массив вызывает бокс/распаковку" показалось мне странным. Это правда? Тем не менее, я предварительно вычислил первичные лучи и поместил их в массив, поэтому я занялся этой статьей и вычислил первичный луч, когда мне это было нужно, и никогда не добавлял их в массив, но ничего не менял: с классов, он был еще в 1,5 раза быстрее.Когда вы запустите этот пример, вы увидите, что цикл структуры на порядок быстрее. Тем не менее, важно остерегаться использования ValueTypes, когда вы рассматриваете их как объекты. Это добавляет дополнительные бокс и unboxing накладные расходы на вашу программу, и может в конечном итоге стоить вам больше, чем если бы вы застряли с объектами! Чтобы увидеть это в действии, измените приведенный выше код, чтобы использовать массив foos и баров. Вы обнаружите, что производительность более или менее одинакова.
Я запускаю .NET 3.5 SP1, который, по моему мнению, исправил проблему, когда методы struct никогда не были связаны друг с другом, поэтому это тоже не может быть.
Итак, в основном: любые советы, вещи, которые нужно учитывать и чего следует избегать?
EDIT: Как было предложено в некоторых ответах, я создал тестовый проект, в котором я попытался передать структуры как ref. Методы добавления двух векторов:
public static VectorStruct Add(VectorStruct v1, VectorStruct v2)
{
return new VectorStruct(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
}
public static VectorStruct Add(ref VectorStruct v1, ref VectorStruct v2)
{
return new VectorStruct(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
}
public static void Add(ref VectorStruct v1, ref VectorStruct v2, out VectorStruct v3)
{
v3 = new VectorStruct(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
}
Для каждого из них я получил вариацию следующего эталонного метода:
VectorStruct StructTest()
{
Stopwatch sw = new Stopwatch();
sw.Start();
var v2 = new VectorStruct(0, 0, 0);
for (int i = 0; i < 100000000; i++)
{
var v0 = new VectorStruct(i, i, i);
var v1 = new VectorStruct(i, i, i);
v2 = VectorStruct.Add(ref v0, ref v1);
}
sw.Stop();
Console.WriteLine(sw.Elapsed.ToString());
return v2; // To make sure v2 doesn't get optimized away because it unused.
}
Кажется, что все они выглядят одинаково. Возможно ли, что они оптимизируются JIT для того, что является оптимальным способом передать эту структуру?
EDIT2: Я должен отметить, что использование структур в моем тестовом проекте составляет примерно на 50% быстрее, чем использование класса. Почему это другое для моего raytracer, которого я не знаю.