简体   繁体   English

为什么LINQ在这个例子中更快

[英]Why is LINQ faster in this example

I wrote the following to test the performance of using foreach vs LINQ : 我写了以下内容来测试使用foreach vs LINQ的性能:

private class Widget
{
    public string Name { get; set; }
}

static void Main(string[] args)
{
    List<Widget> widgets = new List<Widget>();
    int found = 0;

    for (int i = 0; i <= 500000 - 1; i++)
        widgets.Add(new Widget() { Name = Guid.NewGuid().ToString() });

    DateTime starttime = DateTime.Now;

    foreach (Widget w in widgets)
    {
        if (w.Name.StartsWith("4"))
            found += 1;
    }

    Console.WriteLine(found + " - " + DateTime.Now.Subtract(starttime).Milliseconds + " ms");

    starttime = DateTime.Now;
    found = widgets.Where(a => a.Name.StartsWith("4")).Count();

    Console.WriteLine(found + " - " + DateTime.Now.Subtract(starttime).Milliseconds + " ms");

    Console.ReadLine();
}

I get something like following output: 我得到类似以下输出:

31160 - 116ms
31160 - 95 ms

In every run, LINQ outperforms foreach by around 20%. 在每次运行中,LINQ都比foreach高出约20%。 It was my understanding that the LINQ extension methods used standard c# under the covers. 据我所知,LINQ扩展方法使用了标准的c#。

So why is LINQ faster in this case? 那么为什么LINQ在这种情况下会更快?

EDIT: 编辑:

So I changed my code to use stopwatch instead of datetime and still get the same results. 所以我改变了我的代码使用秒表而不是datetime仍然得到相同的结果。 If I run the LINQ query first then my results show LINQ to be about 20% slower then foreach. 如果我先运行LINQ查询,那么我的结果显示LINQ比foreach慢约20%。 This has to be some sort of JIT warmnup issue. 这必须是某种JIT热身问题。 My question is how do I compensate for JIT warmup in my test case? 我的问题是如何在我的测试用例中补偿JIT热身?

It's because you do not have a warmup. 这是因为你没有热身。 If you reverse your cases you will get excatly the opposit result: 如果你扭转案件,你会得到相反的结果:

31272 - 110ms
31272 - 80 ms

Start adding a warmup and use a stopwatch for better timing. 开始添加预热并使用秒表以获得更好的计时。

Running the test with warmup: 用预热运行测试:

        //WARM UP:
        widgets.Where(a => a.Name.StartsWith("4")).Count();

        foreach (Widget w in widgets)
        {
            if (w.Name.StartsWith("4"))
                found += 1;
        }

        //RUN Test
        Stopwatch stopwatch1 = new Stopwatch();
        stopwatch1.Start();

        found = widgets.Where(a => a.Name.StartsWith("4")).Count();
        stopwatch1.Stop();

        Console.WriteLine(found + " - " + stopwatch1.Elapsed);

        found = 0;
        Stopwatch stopwatch2 = new Stopwatch();
        stopwatch2.Start();

        foreach (Widget w in widgets)
        {
            if (w.Name.StartsWith("4"))
                found += 1;
        }
        stopwatch2.Stop();

        Console.WriteLine(found + " - " + stopwatch2.Elapsed);

result: 结果:

31039 - 00:00:00.0783508
31039 - 00:00:00.0766299

I did some profiling a while back, comparing the following: 我做了一段时间的分析,比较以下内容:

  • LINQ to Objects with/without Regex 具有/不具有正则表达式的对象的LINQ

  • Lambda Expressions with/without Regex 带/不带正则表达式的Lambda表达式

  • Traditional iteration with/without Regex 带/不带正则表达式的传统迭代

What I found out was that LINQ, Lambda and Traditional iteration were pretty much the same always, but the real timing difference was in the Regex expressions. 我发现LINQ,Lambda和Traditional迭代总是相同,但真正的时序差异在于Regex表达式。 Only adding the Regex made the evaluation slower (a LOT slower). 只有添加正则表达式才能使评估更慢(慢一点)。 (Details here: http://www.midniteblog.com/?p=72 ) (详情请见: http//www.midniteblog.com/?p = 72

What you are seeing above is probably due to the fact that you are doing both tests in the same code block. 您在上面看到的可能是因为您在同一个代码块中进行了两个测试。 Try commenting one out, timing it, then commenting the other out. 尝试评论一个,计时,然后评论另一个。 Also, make sure you are running a release build, not in the debugger. 此外,请确保您正在运行发布版本,而不是在调试器中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM