使用struct over class可以获得多少性能提升?我应该设计专注于最大限度地使用struct而不是类的应用程序吗?
我可以将我的类转换为struct并在任何可能的地方将函数移动到另一个静态类中吗?
该MSDN具有良好的指向:
✓如果类型的实例很小并且通常是短暂的或通常嵌入在其他对象中,则CONSIDER定义结构而不是类.
X AVOID定义结构,除非该类型具有以下所有特征:
它在逻辑上表示单个值,类似于原始类型(int,double等).
它的实例大小小于16个字节.
这是不可改变的.
它不必经常装箱.
MSDN也有结构设计
我应该设计专注于最大限度地使用struct而不是类的应用程序吗?
这取决于你想要实现的目标.如果您有一个小型结构,而您尝试实现的结构类似于值,则使用结构.所以说在类上使用struct不是一个理想的陈述或方法.
msdn建议(在另一个答案中列出)提供了一些指导.对于性能,您应该考虑它们的用法以及结构和类之间的区别.最重要的是当类型是实际值类型时才使用结构,即具有值语义.对于值类型使用类,或者对于应该是引用类型的结构使用结构将很快给出无法复制或非预期引用的混乱结果.还要记住结构应该始终是不可变的.
只有在性能极为敏感的情况下才应忽略这些基本规则(例如:框架违反了List.Enumerator结构的规则!).
结构与类的Perf注意事项:
如果将结构作为参数传递给方法,则每次都会创建结构的副本.这就是为什么文档建议不要使结构大于16个字节.
double Distance(Vector3D a, Vector3D b) // Copies both 24-byte structs { return Math.Sqrt((a.X - b.X *....); }
在上面的场景中,3个双打的3D矢量会产生24个字节并且会比建议的16个大,但我仍然认为结构是有意义的,因为它显然是一个值类型,特别是你有一个包含两个的Vector2D双打(16字节)是一个结构!
有效地使用结构的关键,以及它们的性能真正发挥作用的关键是将它们用于缓存局部性并避免许多分配.要重复使用上面的Vector示例,如果您有此方法
double AverageDistanceFromOrigin(Vector3D[] points) // Single reference passed { double sum = 0.0; for(...) sum += Math.Sqrt(points[i].X... + ... + ...) // No copies return sum/points.Length; }
您可能会看到有利于结构的良好性能差异.原因是现在您将单个引用(数组)传递给方法,因此每次调用复制struct时没有额外的开销(请注意,该方法不会为数组中的每个条目调用distance-method) .
结构数组也在内存中连续布局,如[x1,y1,z1,x2,y2,...],因此cpu将一次加载例如16个坐标进入缓存,导致很少的缓存未命中.将其与class Vector3D
实现进行比较:现在将分配一个向量数组,并且数组中的每个条目也将是必须进行堆分配的引用,以后再进行垃圾回收.该数组现在是一个引用数组[ref to v1,ref to v2,ref to v3],每个引用都可能在堆中有任何地址,并且可能不会彼此相邻.这可能导致比结构案例更多的缓存未命中.
仅当您的类型具有值语义时才使用结构(反之亦然).
不要将大型结构单独传递给方法; 对结构的列表/数组进行操作以避免复制
不要将16字节限制视为硬限制:您可以使用更大的结构,但请记住避免将它们单独传递给方法.