【发布时间】:2010-10-02 21:37:31
【问题描述】:
编辑:我向大家道歉。当我实际上想说“多维数组”时,我使用了“锯齿状数组”一词(如下面的示例所示)。对于使用错误的名称,我深表歉意。我实际上发现锯齿状数组比多维数组更快!我已经添加了锯齿状数组的测量值。
我今天尝试使用 jagged 多维数组时,发现它的性能不如我预期。使用一维数组并手动计算索引比使用二维数组快得多(几乎是两倍)。我使用1024*1024 数组(初始化为随机值)编写了一个测试,进行了 1000 次迭代,我在我的机器上得到了以下结果:
sum(double[], int): 2738 ms (100%)
sum(double[,]): 5019 ms (183%)
sum(double[][]): 2540 ms ( 93%)
这是我的测试代码:
public static double sum(double[] d, int l1) {
// assuming the array is rectangular
double sum = 0;
int l2 = d.Length / l1;
for (int i = 0; i < l1; ++i)
for (int j = 0; j < l2; ++j)
sum += d[i * l2 + j];
return sum;
}
public static double sum(double[,] d) {
double sum = 0;
int l1 = d.GetLength(0);
int l2 = d.GetLength(1);
for (int i = 0; i < l1; ++i)
for (int j = 0; j < l2; ++j)
sum += d[i, j];
return sum;
}
public static double sum(double[][] d) {
double sum = 0;
for (int i = 0; i < d.Length; ++i)
for (int j = 0; j < d[i].Length; ++j)
sum += d[i][j];
return sum;
}
public static void Main() {
Random random = new Random();
const int l1 = 1024, l2 = 1024;
double[ ] d1 = new double[l1 * l2];
double[,] d2 = new double[l1 , l2];
double[][] d3 = new double[l1][];
for (int i = 0; i < l1; ++i) {
d3[i] = new double[l2];
for (int j = 0; j < l2; ++j)
d3[i][j] = d2[i, j] = d1[i * l2 + j] = random.NextDouble();
}
//
const int iterations = 1000;
TestTime(sum, d1, l1, iterations);
TestTime(sum, d2, iterations);
TestTime(sum, d3, iterations);
}
进一步调查表明,第二种方法的 IL 比第一种方法大 23%。 (代码大小 68 与 52。)这主要是由于对 System.Array::GetLength(int) 的调用。编译器还会为 jagged 多维数组发出对 Array::Get 的调用,而它只是为简单数组调用 ldelem。
所以我想知道,为什么通过多维数组访问比普通数组慢?我会假设编译器(或 JIT)会做一些类似于我在第一个方法中所做的事情,但事实并非如此。
您能帮我理解为什么会这样吗?
更新:按照 Henk Holterman 的建议,这里是 TestTime 的实现:
public static void TestTime<T, TR>(Func<T, TR> action, T obj,
int iterations)
{
Stopwatch stopwatch = Stopwatch.StartNew();
for (int i = 0; i < iterations; ++i)
action(obj);
Console.WriteLine(action.Method.Name + " took " + stopwatch.Elapsed);
}
public static void TestTime<T1, T2, TR>(Func<T1, T2, TR> action, T1 obj1,
T2 obj2, int iterations)
{
Stopwatch stopwatch = Stopwatch.StartNew();
for (int i = 0; i < iterations; ++i)
action(obj1, obj2);
Console.WriteLine(action.Method.Name + " took " + stopwatch.Elapsed);
}
【问题讨论】:
-
不久前,我发现了一篇博客文章,其中需要优化矩阵求逆(或类似的东西)。结果证明,锯齿状数组比多维数组快得多。我不记得是哪个博客了。
-
这是内置发布模式并进行了优化吗?
-
是的@Justice,它是,从命令行运行,进程优先级设置为实时,线程优先级设置为最高。
-
你确定这段代码真的被 JIT 编译器优化了吗?
标签: .net performance arrays