Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/github/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 结构是什么时候的答案?_C#_Performance_Struct_Raytracing_Struct Vs Class - Fatal编程技术网

C# 结构是什么时候的答案?

C# 结构是什么时候的答案?,c#,performance,struct,raytracing,struct-vs-class,C#,Performance,Struct,Raytracing,Struct Vs Class,我正在做一个光线跟踪器的爱好项目,最初我对向量和光线对象使用结构,我认为光线跟踪器是使用它们的最佳情况:你创建了数以百万计的光线跟踪器,它们的寿命不超过一种方法,它们是轻量级的。然而,通过简单地将Vector和Ray上的“struct”更改为“class”,我获得了非常显著的性能提升 有什么好处?它们都很小(矢量为3个浮点数,射线为2个矢量),不要被过度复制。当然,我会在需要时将它们传递给方法,但这是不可避免的。那么,在使用结构时,哪些常见的陷阱会破坏性能呢?我读过MSDN的文章,上面说: 当您

我正在做一个光线跟踪器的爱好项目,最初我对向量和光线对象使用结构,我认为光线跟踪器是使用它们的最佳情况:你创建了数以百万计的光线跟踪器,它们的寿命不超过一种方法,它们是轻量级的。然而,通过简单地将Vector和Ray上的“struct”更改为“class”,我获得了非常显著的性能提升

有什么好处?它们都很小(矢量为3个浮点数,射线为2个矢量),不要被过度复制。当然,我会在需要时将它们传递给方法,但这是不可避免的。那么,在使用结构时,哪些常见的陷阱会破坏性能呢?我读过MSDN的文章,上面说:

当您运行这个示例时,您将看到struct循环快了几个数量级。但是,当您将ValueTypes视为对象时,一定要小心使用它们。这会给您的程序增加额外的装箱和拆箱开销,并且最终会比您使用对象时花费更多的成本!要查看此操作,请修改上面的代码以使用foo和bar数组。你会发现性能大致相当

但是它已经很老了(2001年),整个“把它们放在一个数组中会导致装箱/拆箱”让我觉得很奇怪。这是真的吗?但是,我确实预先计算了主光线并将其放入数组中,因此我开始阅读本文,在需要时计算主光线,并且从未将其添加到数组中,但这并没有改变任何事情:使用类时,速度仍然快1.5倍

我运行的是.NET3.5SP1,我相信它解决了一个结构方法从来都没有出现过的问题,所以这也不可能

基本上:任何小窍门、需要考虑的事情和应该避免的事情?

编辑:正如一些答案中所建议的,我已经建立了一个测试项目,在该项目中我尝试将结构作为参考传递。添加两个向量的方法:

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's unused. 
}
vectorStructTest()
{
秒表sw=新秒表();
sw.Start();
var v2=新的向量结构(0,0,0);
对于(int i=0;i<100000000;i++)
{
var v0=新向量结构(i,i,i);
var v1=新向量结构(i,i,i);
v2=矢量结构添加(参考v0,参考v1);
}
sw.Stop();
Console.WriteLine(sw.appeased.ToString());
return v2;//确保v2未被优化,因为它未被使用。
}
它们的表现似乎几乎相同。有没有可能通过JIT将它们优化为传递此结构的最佳方式


EDIT2:我必须注意,在我的测试项目中使用结构比使用类快50%。我不知道为什么我的光线跟踪器不同

在.NET泛型之前写的任何关于装箱/拆箱的文章都可以略作保留。泛型集合类型已经不再需要对值类型进行装箱和取消装箱,这使得在这些情况下使用结构更有价值


至于您的特定减速-我们可能需要查看一些代码。

基本上,不要将它们设置得太大,并在可能的情况下通过ref传递它们。我是用同样的方法发现的。。。通过将向量和光线类更改为结构


随着更多的内存被传递,它必然会导致缓存抖动。

我认为关键在于你文章中的以下两个陈述:

你创造了数百万个

当然,我会在需要时将它们传递给方法


现在,除非您的结构大小小于或等于4个字节(如果您在64位系统上,则为8个字节),否则,如果您只传递了一个对象引用,则每次方法调用都会复制更多的内容。

您还可以将结构设为可为空的对象。无法创建自定义类

作为

Nullable xxx=新的Nullable
其中,具有结构的可为空

Nullable<MyCustomStruct> xxx = new Nullable<MyCustomStruct>
Nullable xxx=新的Nullable

但是(显然)您将丢失所有继承功能

您分析过应用程序了吗?分析是查看实际性能问题所在的唯一可靠方法。在结构上,有些操作通常更好/更差,但除非您对其进行分析,否则您只能猜测问题出在哪里

我要寻找的第一件事是确保您已经显式地实现了Equals和GetHashCode。如果做不到这一点,则意味着每个结构的运行时实现都会执行一些非常昂贵的操作来比较两个结构实例(在内部,它使用反射来确定每个私有字段,然后检查它们是否相等,这会导致大量的分配)


一般来说,你能做的最好的事情是在分析器下运行你的代码,看看那些慢的部分在哪里。这可能是一次令人大开眼界的体验。

在关于何时使用结构的建议中,它指出结构不应大于16字节。你的向量是12字节,接近极限。射线有两个向量,即24字节,这显然超出了建议的限制

当一个结构大于16字节时,不能再使用一组指令有效地复制它,而是使用循环。因此,通过传递这个“魔法”限制,当传递一个结构时,实际上要比传递一个对象的引用时做更多的工作。这就是为什么即使在分配对象时有更多的开销,代码使用类也会更快


向量仍然可以是一个结构,但光线太大,无法很好地用作结构。

我基本上将结构用于参数对象,从函数返回多条信息,然后。。。没有别的了。不知道它是“对”还是“错”,但我就是这么做的。

结构数组将是内存中的单个连续结构,而对象数组中的项(引用类型的实例)需要由
Nullable<MyCustomStruct> xxx = new Nullable<MyCustomStruct>