在遍历数组后加速查找的方法?

8

我有一个123MB大小的int数组,主要用于以下方式:

private static int[] data = new int[32487834]; 
static int eval(int[] c)
{
    int p = data[c[0]];
    p = data[p + c[1]];
    p = data[p + c[2]];
    p = data[p + c[3]];
    p = data[p + c[4]];
    p = data[p + c[5]];
    return data[p + c[6]];
}
eval()被不同的c调用了很多次(约50亿次),我想知道是否可以(以及如何)加快速度。我已经使用了一个使用固定数组的不安全函数,它利用了所有的CPU。它是RayW的TwoPlusTwo 7卡评估器的C#移植版。C++版本略微更快。可以利用GPU来加速吗?

我已经完成了。 - Sven
“insignificantly faster”是什么意思? - leppie
@leppie:我没有针对TwoPlusTwo评估器的多核版本随机手牌程序,但我的C#解决方案大约需要160ms来枚举全部1.33亿手牌,而我发现的C++则需要327毫秒。我更感兴趣的是随机评估,但我不熟练于定制现有的评估器。 - Sven
@igrimpe,确实,例如AsKd vs QdQh,几千次评估就足够了,但如果你想要范围对范围,你需要大量的评估。这样做很多次,速度不可能快到哪里去。 - Sven
你是否预先知道数组的内容?或者你能以某种方式预测p的值吗?根据它的值,你的代码可能会非常低效,因为你可能没有充分利用处理器的缓存。 - Żubrówka
显示剩余5条评论
1个回答

2
  1. 将数组引用缓存到本地变量中。与静态字段相比,局部变量通常更慢,有多个原因(其中之一是字段可能会更改,因此必须一直重新加载。JIT可以更自由地优化本地变量)。
  2. 不要将数组用作方法的参数。硬编码7个整数索引。这减少了数组分配、间接惩罚和边界检查。
  3. 使用不安全代码索引数组。这将消除边界检查。使用GCHandle来修复数组,并将指针缓存到静态字段中(不要只使用固定块-我认为它具有某些(小)与进入它相关的开销。不确定)。
  4. 作为固定数组的替代方案,使用VirtualAlloc分配123MB数组并使用大页面。这样可以减少TLB失效。

所有这些都是强制性的低级优化。它们仅适用于需要最大性能的情况。

我认为在优化此函数时,我们已经达到了极限。如果您显示函数的调用者,以便可以将其作为单个单元进行优化,那么我们可能只能做得更好。


谢谢您的建议。我知道其中一些词语,这需要更多的研究;) - Sven
这是当前的初始化,有什么建议吗?我不确定这是否是正确的位置。 - Sven
看起来不错。现在你可以将HR数组更改为指向使用VirtualAlloc分配的带有MEM_LARGE_PAGES参数的缓冲区的int*。你需要使用memcpy将数据复制到该缓冲区,并在计算中使用该缓冲区。 - usr
好的,再次看到这些词语我知道它们是什么意思。很抱歉,但谷歌完全没有帮助。你可能想让我使用P/Invoke与那些C++函数一起使用,但我找不到一个相关的例子。我应该就此提出一个新问题吗?还是你能帮我解决这个问题? - Sven
@BeatMe 我明白了。如果文档(http://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx)不能帮助你(我认为它们很好),我建议你问一下“如何在C#中使用VirtualAlloc分配和使用本地内存?”我认为你会得到比我能在几行中提供的更全面的答案。如果你提到你还不熟练使用不安全代码,你可能会得到非常实用的答案。不过,你可以在这里发布问题链接。 - usr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接