13
我有一些奇怪的性能結果,我無法完全解釋。 看來,這個線多維陣列初始化器的性能下降
d = new double[4, 4]{{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1},};
比這個
d = new double[4, 4];
d[0, 0] = 1; d[0, 1] = 0; d[0, 2] = 0; d[0, 3] = 0;
d[1, 0] = 0; d[1, 1] = 1; d[1, 2] = 0; d[1, 3] = 0;
d[2, 0] = 0; d[2, 1] = 0; d[2, 2] = 1; d[2, 3] = 0;
d[3, 0] = 0; d[3, 1] = 0; d[3, 2] = 0; d[3, 3] = 1;
慢4倍(這甚至沒有考慮到一個事實,在這個例子中,我可以離開了所有那些= 0
分配)
我知道在c#中的多維數組上循環會因邊界檢查而變慢。但是這裏沒有循環,不需要邊界檢查,整個數組初始化行可以在編譯時解析。
然而,第二個代碼塊必須首先將數組初始化爲零,然後分別覆蓋每個值。
那麼這裏有什麼問題?
如果性能是一個問題,那麼初始化這個數組的最佳方法是什麼?
我用下面的代碼來衡量性能:
using System;
using System.Diagnostics;
class Program
{
public static double[,] d; // global static variable to prevent the JIT optimizing it away
static void Main(string[] args)
{
Stopwatch watch;
int numIter = 10000000; // repeat all tests this often
double[,] d2 = new double[4, 4]{{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1},};
// ================================================================
// use arrayInitializer: slowest
watch = Stopwatch.StartNew();
for (int i = 0; i < numIter; i++)
{
d = new double[4, 4]{{1, 0, 0, 0},
{0, 1, 0, 0},
{0, 0, 1, 0},
{0, 0, 0, 1},};
}
Console.WriteLine("ArrayInitializer: \t{0:0.##########}ms", watch.ElapsedMilliseconds * 1.0/numIter);
// ================================================================
// use Array.Copy: faster
watch = Stopwatch.StartNew();
for (int i = 0; i < numIter; i++)
{
d = new double[4, 4];
Array.Copy(d2, d, d2.Length);
}
Console.WriteLine("new + Array.Copy: \t{0:0.##########}ms", watch.ElapsedMilliseconds * 1.0/numIter);
// ================================================================
// direct assignment: fastest
watch = Stopwatch.StartNew();
for (int i = 0; i < numIter; i++)
{
d = new double[4, 4];
d[0, 0] = 1; d[0, 1] = 0; d[0, 2] = 0; d[0, 3] = 0;
d[1, 0] = 0; d[1, 1] = 1; d[1, 2] = 0; d[1, 3] = 0;
d[2, 0] = 0; d[2, 1] = 0; d[2, 2] = 1; d[2, 3] = 0;
d[3, 0] = 0; d[3, 1] = 0; d[3, 2] = 0; d[3, 3] = 1;
}
Console.WriteLine("direct assignment: \t{0:0.##########}ms", watch.ElapsedMilliseconds * 1.0/numIter);
}
}
結果:
ArrayInitializer: 0,0007917ms
new + Array.Copy: 0,0002739ms
direct assignment: 0,0002281ms
看看編譯的IL代碼是非常不同的。 ArrayInitializer使用一種方法RuntimeHelpers.InitializeArray。但那是我能做的最好的...有趣的問題! – Aron
您從不使用創建的數組,所以整個數組分配是否會被編譯器優化掉? – Servy
這就是爲什麼我使數組公共靜態。如果它只是一個局部變量,那麼它確實被優化了,但只適用於數組初始值設定項的第一個測試用例。但是如果'd'是一個靜態變量,則不應該有這樣的優化,因爲另一個線程可以想象得到它;時間測試似乎證實了這一點。 – HugoRune