我遇到一個非常有趣的情況,比較一個泛型方法內可空類型爲null比比較值類型或引用類型慢234倍。代碼如下:爲什麼在沒有約束的泛型方法上比較可空值類型爲null會慢些?
static bool IsNull<T>(T instance)
{
return instance == null;
}
的執行代碼是:
int? a = 0;
string b = "A";
int c = 0;
var watch = Stopwatch.StartNew();
for (int i = 0; i < 1000000; i++)
{
var r1 = IsNull(a);
}
Console.WriteLine(watch.Elapsed.ToString());
watch.Restart();
for (int i = 0; i < 1000000; i++)
{
var r2 = IsNull(b);
}
Console.WriteLine(watch.Elapsed.ToString());
watch.Restart();
for (int i = 0; i < 1000000; i++)
{
var r3 = IsNull(c);
}
watch.Stop();
Console.WriteLine(watch.Elapsed.ToString());
Console.ReadKey();
對於上述代碼的輸出是:
00:00:00.1879827
00:00: 00.0008779
00:00:00.0008532
正如你所看到的,比較一個可爲null的int與null比比較一個int或一個字符串慢234倍。如果我添加了第二個過載與正確的約束,結果發生顯着變化:
static bool IsNull<T>(T? instance) where T : struct
{
return instance == null;
}
現在的結果是:
00:00:00.0006040
00:00:00.0006017
00:00:00.0006014
這是爲什麼?我沒有檢查字節碼,因爲我不太流利,但即使字節碼有點不同,我期望JIT優化這個,而不是(我正在運行優化) 。
有了這樣的結果 - 在最差的情況下進行1M次迭代的時間低於0.2秒,是否重要? – Oded 2011-04-18 19:30:36
是的,如果你每秒鐘做這個1M的話。我做。 – 2011-04-18 19:43:02
不要忘記,您正在衡量百萬次迭代*的成本和第一次調用*上代碼的成本之和。如果代碼真的很便宜,就像這段代碼一樣,只發生一次的jit成本實際上可以支配平均值。在同一個程序中運行兩次測試可能會很有趣,所以第二次,代碼是「熱門」。 – 2011-04-18 20:05:13