2013-04-25 24 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

相关问题