C#优化 - 值类型的数组/列表和堆栈(游戏)

时间:2012-01-29 22:51:22

标签: c# optimization

我正在开发一款游戏,而且正处于一个AI数字运算中间,我想尽可能地优化代码。我在我的代码中有几个结构,如Circle,Vector等。我希望通过此代码将GC的负载降至最低,因为它将每秒运行多次,并且在每次调用时将生成几个大型数组,执行大量计算。

我的问题是,如果我有一个可以“返回”多个值类型的小方法(即圆和向量的交集等),那么将其结果传回主方法的最高效方法是什么?

我可以想到几种方法:

  • 返回结果数组,即Vector []
  • 返回列表< Vector>
  • 传入列表< Vector>
  • 任何其他方式..?

什么是避免GC必须收集的堆上许多小的不必要的对象/数组的最佳策略?

3 个答案:

答案 0 :(得分:7)

如果您遇到以下情况:

  • 您经常调用此方法
  • 您将始终处理相同大小的集合(或类似,至少)
  • 下次调用时,您不需要以前的结果

...然后你可能能够通过重复传入相同的数组(或List<T>)并修改它来提高性能。另一方面,在进行任何更改之前,您应该绝对测量的性能。你还应该确定将会是什么&#34;足够好&#34;因此,您不必将代码从最自然的设计中折弯出去,而不是必须。

答案 1 :(得分:2)

这取决于您传递的数据类型,大多数时候游戏都使用了向量,交集数据等结构......

当数据是结构时,你应该避免List<T>并传递每个值,因为数据被复制了。但这在很大程度上依赖于代码,有时候每个值传递可能会更快,有时则不会。我会做一些性能测试。您可以在没有分析器的情况下将此方法用于简单测试:

public static Int64 MeasureTime(Action myAction)
{
    var stopWatch = new Stopwatch();
    stopWatch.Start();
    myAction();
    stopWatch.Stop();
    return stopWatch.ElapsedMilliseconds;
}

在处理结构时,使用outref可能总是一种好方法。

更多信息

所有这些情况都可能不会导致性能问题,它们只是解释我在使用结构时学到的最佳实践。要确定refout在每种情况下是否有用,都应进行性能测试。

ref 用于避免此类情况:

Vector input = new Vector(x, y, z);
input = ModifyVector(input); // This line causes copies of the input vector and it's slow

这里的性能取决于Vector类的大小,每次使用以下方法都不是一个好习惯。返回一个简单的Int32时,它不是必需的,不应该用来保持代码的可读性。

正确的方式:

Vector input = new Vector(x, y, z);
ModifyVector(ref input);

当然ref关键字可以用来使方法更快,什么都不返回,但是这种方法必须注意传递给它们的数据,并且应该避免修改它们。在某些情况下,速度优势可能超过50%(我有一个高性能的矢量库,我测试了很多情况)。

out 用于避免此类情况:

Ray ray = ...;
CollisionData data = CastRay(ref ray); // Note the ref here to pass the Ray which contains 6 floats

CollisionData至少包含它撞击地面的点和法线。在这里使用out来获得结果时,它应该更快。

正确的方式:

Ray ray = ...;
CollisionData data;
CastRay(ref ray, out data);

使用数组时..

..您应该知道数组已经是一个引用,并且您不需要refout关键字来处理它们。但是在使用结构时,您应该知道您没有保存数组中结构的引用。因此,当修改数组的值时,您可以使用ref myArray[0]将值传递给方法,并在索引零处修改结构而不复制它。还要避免创建它们的新实例。

答案 2 :(得分:0)

不知道你的平台/框架是什么(XNA?),但我在Windows Phone 7下遇到了GC的问题(7.5有代际GC,但没有测试过)。为了避免所谓的GC冻结,我制作了一个集合,我将所有必要的数据预先加载到Dictionary中。

但首先是衡量措施措施。