2013-04-25 56 views
0

我第一次運行下面的代碼:爲什麼LINQ需要更多的時間來執行而不是foreach?

var stringList = new[]{"A","BB","CCC","DDDD"}; 
var dictionary = new Dictionary<int, string>(); 
var stopwatch = new Stopwatch(); 
stopwatch.Start(); 
foreach (var s in stringList) 
{ 
    dictionary.Add(s.Length,s); 
} 
stopwatch.Stop(); 
Console.WriteLine(stopwatch.Elapsed); 
Console.ReadKey(); 

執行時間爲:00:00:00.0000205

然後我跑到下面的代碼...

var stringList = new[]{"A","BB","CCC","DDDD"}; 
var stopwatch = new Stopwatch(); 
stopwatch.Start(); 
var dictionary = stringList.ToDictionary(s => s.Length); 
stopwatch.Stop(); 
Console.WriteLine(stopwatch.Elapsed); 
Console.ReadKey(); 

執行時間爲:00 :00:00.0037431

這是否證明foreach比LINQ好?

+8

不,它證明了寫性能測試並不像你的情況顯示非易事。 – I4V 2013-04-25 08:12:34

+4

@Atish,運行這個測試100000次,並做平均。 ,然後在帶有100000個隨機字符串的字符串列表上運行這幾十次併發布結果 – Nahum 2013-04-25 08:12:50

+2

如果您要執行微基準測試,您應該使用較大的數據集來抵消預熱成本。 – 2013-04-25 08:13:12

回答

2

有幾件事情錯了你的例子:

  • 微小的樣本大小。數組中的四個元素?嘗試1,000,000
  • 在第一個示例中,字典對象是在秒錶外之外創建的。創建對象是速度的一個因素,特別是對於這樣一個小例子
  • LINQ代碼使用委託。無可否認,這是LINQ中的常見用法,但要獲得真正的比較,兩者都應該使用方法,或者兩者都應該使用委託。

你應該看看喬恩斯基特在這個問題上的blog post

2

這是否證明foreach比LINQ好?

不,它證明它更快。

更好的是一種主觀的概念。例如,如果您希望更具可讀性和更緊湊的代碼,並且性能不是該項目的最高優先級,並且已確定這不是瓶頸,那麼LINQ可能實際上會更好。

+0

我怎麼能看到他們之間的表現? – 2013-04-25 08:18:47

+0

你已經看到了。這是一個小小的區別,你可能不應該擔心,除非你正在做一些微觀優化。 – 2013-04-25 08:22:10

+0

不,它只能證明它在這種特殊情況下更快。 – Rik 2013-04-25 08:22:29

2

你可以看到如何ToDictionary看起來真的使用.NET源或ILSpy:

public static Dictionary<TKey, TElement> ToDictionary<TSource, TKey, TElement>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, Func<TSource, TElement> elementSelector, IEqualityComparer<TKey> comparer) 
{ 
    if (source == null) 
    { 
     throw Error.ArgumentNull("source"); 
    } 
    if (keySelector == null) 
    { 
     throw Error.ArgumentNull("keySelector"); 
    } 
    if (elementSelector == null) 
    { 
     throw Error.ArgumentNull("elementSelector"); 
    } 

    Dictionary<TKey, TElement> dictionary = new Dictionary<TKey, TElement>(comparer); 
    foreach (TSource current in source) 
    { 
     dictionary.Add(keySelector(current), elementSelector(current)); 
    } 
    return dictionary; 
} 

正如你所看到的,它使用foreach太!但是,參數檢查和Func代表使得您的自定義代碼效率稍低一點,只需調用Dictionary.Add方法。不過,我認爲在實際應用中罰款使用ToDictionary而不是自定義foreach並不重要。

0

爲什麼?

因爲沒有魔法,LINQ版本比非LINQ版本做了很多處理。

我寫了一小段代碼,顯示了LINQ在內部做了什麼。你可以看到幾乎相同的表演。也不要注意我已經添加了字典的實例內循環:

int testCount = 1000000; 
var stringList = new[] { "A", "BB", "CCC", "DDDD" }; 

Func<string, string> elementSelector = (value) => value; 

var stopwatch = Stopwatch.StartNew(); 

for (int i = 0; i < testCount; i++) 
{ 
    var dictionary = new Dictionary<int, string>(); 
    Func<string, int> keySelector = (value) => value.Length; 
    foreach (var s in stringList) 
    { 
     if (keySelector != null && elementSelector != null) 
     { 
      dictionary.Add(keySelector(s), elementSelector(s)); 
     } 
    } 
} 

stopwatch.Stop(); 
Console.WriteLine(stopwatch.Elapsed.TotalMilliseconds/testCount); 

var stopwatch2 = Stopwatch.StartNew(); 

for (int i = 0; i < testCount; i++) 
{ 
    var dictionary2 = stringList.ToDictionary(s => s.Length); 
} 

stopwatch2.Stop(); 
Console.WriteLine(stopwatch2.Elapsed.TotalMilliseconds/testCount); 

Console.ReadKey(); 
+0

在你的例子中linq也需要更多時間 – 2013-04-25 08:35:38

+0

@AtishDipongkor當然,因爲有一些額外的處理我沒有寫。基本上,它檢查擴展方法的所有參數是否有效(測試null是否相等)。我寫的非LINQ版本提供*類似*結果 – ken2k 2013-04-25 08:37:13

相關問題