1

为了最大化关键方法的性能,在另一个问题中,有人建议我本地分配和使用数组的内存,而不是修复它。

我在 C# 中工作,没有使用不安全代码和使用 P/invoke 的经验。我在谷歌上没有找到任何相关的例子,关于 VirtualAlloc 的 MSDN 文章也没有帮助。

这是一种被称为数十亿次的方法,并且每一点性能都是可取的。

    public static readonly int[] HR = new int[32487834];
    public unsafe int eval(int c1, int c2, int c3, int c4, int c5, int c6, int c7)
    {
        fixed (int* HR = Evaluator.HR)
        {
            int p = HR[53 + c1];
            p = HR[p + c2];
            p = HR[p + c3];
            p = HR[p + c4];
            p = HR[p + c5];
            p = HR[p + c6];
            return (HR[p + c7]);
        }
    }

如果您有兴趣,它是TwoPlusTwo-Evaluator的 C# 端口,它使用 123mb 查找表返回随机 7 张扑克手牌的排名以进行比较。在我的机器上,我以随机顺序平均大约 80M 评估/秒,以连续顺序平均 500M 评估/秒(c1=0,c2=1,循环将每个变量增加到 52)。

4

2 回答 2

1

您的示例的主要问题是您必须使用循环代码外部fixed的指令。在这个嵌套函数中使用它并没有真正的帮助,而且可能会使事情变得更糟,因为它会使 C# 在内部调用其 GC 内存固定 API。所以一个更好的解决方案应该有这样的代码:

public unsafe int eval(int* HR, int c1, int c2, int c3, int c4, int c5, int c6, int c7)
{
    int p = HR[53 + c1];
    p = HR[p + c2];
    p = HR[p + c3];
    p = HR[p + c4];
    p = HR[p + c5];
    p = HR[p + c6];
    return (HR[p + c7]);
}

fixed本质上是GCHandle.AddrOfPinnedObject的语言构造同义词。在您的情况下,忽略对八个数组进行的边界检查超过了每次输入该函数时通过 GC 固定和取消固定内存的成本......但可能不会太多。

使用 P/Invoke 通常并非易事,除非您想花几天时间熟悉该领域,否则我建议您不要使用它。如果您还不熟悉通过 C++ 进行的 Win32/WinAPI 编程,则更具挑战性。最好重新编写您的代码,以便您可以将内存固定在链上尽可能高的位置。出于这个特定目的,您甚至可以为该数组创建一个 GCHandle 作为对象构造函数的一部分。

于 2012-12-31T23:54:52.690 回答
0

尝试使用 C++/Cli:

ref class Evaluator
{
public:
  static Int32* HR;
  static Evaluator()
  {
    int size = 32487834;
    HR = (INT*)malloc(size * 4);
  }

  static Int32 Eval(Int32 c1, Int32 c2, Int32 c3, Int32 c4, Int32 c5, Int32 c6, Int32 c7)
  {
      Int32 p = HR[53 + c1];
      p = HR[p + c2];
      p = HR[p + c3];
      p = HR[p + c4];
      p = HR[p + c5];
      p = HR[p + c6];
      return (HR[p + c7]);

  }
};
于 2012-12-31T01:07:07.890 回答