为什么LINQ比foreach花费更多时间执行?

时间:2013-04-25 08:10:07

标签: c# linq

我先运行以下代码:

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更好?

4 个答案:

答案 0 :(得分:2)

  

它是否证明foreach比LINQ更好?

不,它证明它更快。

更好的是主观概念。例如,如果您希望拥有更具可读性和紧凑性的代码,并且性能不是项目的最高优先级,并且已经确定这不是瓶颈,那么LINQ实际上可能会更好。

答案 1 :(得分:2)

您的示例有几个问题:

  • 小样本量。数组中的四个元素??尝试1,000,000
  • 在第一个示例中,词典对象在秒表的外部处创建。对象创建是速度的一个因素,特别是在这么小的例子中
  • LINQ代码使用委托。不可否认,这是LINQ中的常见用法,但要获得真正的比较,要么两者都应该使用方法,要么两者都应该使用委托。

你应该看看Jon Skeet关于这个主题的blog post

答案 2 :(得分:2)

您可以看到使用.NET源或ILSpy ToDictionary的真实外观:

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惩罚并不重要。

答案 3 :(得分: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();