我发现,与平面阵列访问相比,字典查找可能会非常慢。知道为什么吗?我正在使用Ants Profiler进行性能测试。这是一个重现问题的示例函数:
private static void NodeDisplace()
{
var nodeDisplacement = new Dictionary<double, double[]>();
var times = new List<double>();
for (int i = 0; i < 6000; i++)
{
times.Add(i * 0.02);
}
foreach (var time in times)
{
nodeDisplacement.Add(time, new double[6]);
}
var five = 5;
var six = 6;
int modes = 10;
var arrayList = new double[times.Count*6];
for (int i = 0; i < modes; i++)
{
int k=0;
foreach (var time in times)
{
for (int j = 0; j < 6; j++)
{
var simpelCompute = five * six; // 0.027 sec
nodeDisplacement[time][j] = simpelCompute; //0.403 sec
arrayList[6*k+j] = simpelCompute; //0.0278 sec
}
k++;
}
}
}
注意平面阵列访问和字典访问之间的相对大小?在考虑了数组索引操作(6*k+j
)之后,平面数组比字典访问快了约20倍(0.403 / 0.0278)。
虽然听起来很奇怪,但字典查找占据了我的大部分时间,我必须对其进行优化。
答案 0 :(得分:15)
是的,我并不感到惊讶。词典的意思是它们习惯于查找任意键。考虑单个数组解除引用会发生什么:
非常,非常快。现在进行字典查找(非常粗略;取决于实现):
如果你有“密钥”,可以很容易被用作数组索引(例如连续的整数,或者很容易映射到连续整数的东西那么那将是非常非常快的。这不是哈希表的主要用例。它们适用于无法以这种方式轻松映射的情况 - 例如按字符串查找,或通过任意 double
值(而不是双倍)它们是均匀间隔的,因此可以很容易地映射到整数。
我会说你的标题是误导性的 - 这不是字典查找速度慢,而是当数组是一种更合适的方法时,它们的速度非常快。
答案 1 :(得分:2)
另外Jon's answer我想补充一点,你的内循环不是很多,通常你在内循环中至少做了一些工作,然后字典的相对性能损失有所降低
如果你在Reflector中查看Double.GetHashCode()
的代码,你会发现它正在执行4行代码(假设你的double不是0),这只是你内部循环的主体。 Dictionary<TKey, TValue>.Insert()
(由设置索引器调用)甚至是更多代码,几乎是屏幕已满。
与平面数组相比,使用Dictionary的事情是,当密钥不密集时(例如在你的情况下),你不会浪费太多内存,而且读取和写入都是像数组一样的O(1)(但是有一个更高的常数)。
作为旁注,您可以使用多维数组而不是6*k+j
技巧
以这种方式声明
var arrayList = new double[times.Count, 6];
并以这种方式使用
arrayList[k ,j] = simpelCompute;
它不会更快,但更容易阅读。