15

我写了以下内容来测试使用foreachvs的性能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();
}

我得到类似以下输出的东西:

31160 - 116 毫秒
31160 - 95 毫秒

在每次运行中,LINQ 的性能都比 foreach 高 20% 左右。据我了解,LINQ 扩展方法在幕后使用了标准 c#。

那么为什么在这种情况下 LINQ 更快呢?

编辑:

因此,我将代码更改为使用秒表而不是日期时间,但仍然得到相同的结果。如果我先运行 LINQ 查询,那么我的结果显示 LINQ 比 foreach 慢 20%。这必须是某种 JIT 预热问题。我的问题是如何在我的测试用例中补偿 JIT 预热?

4

2 回答 2

15

那是因为你没有热身。如果你扭转你的情况,你会得到相反的结果:

31272 - 110ms
31272 - 80 ms

开始添加热身并使用秒表以获得更好的时间。

使用预热运行测试:

        //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);

结果:

31039 - 00:00:00.0783508
31039 - 00:00:00.0766299
于 2013-06-17T13:10:36.597 回答
2

不久前我做了一些分析,比较了以下内容:

  • LINQ to Objects 带/不带正则表达式

  • 带/不带正则表达式的 Lambda 表达式

  • 带有/不带正则表达式的传统迭代

我发现 LINQ、Lambda 和传统迭代几乎总是相同的,但真正的时间差异在于 Regex 表达式。仅添加正则表达式会使评估变慢(慢很多)。(详情请见:http: //www.midniteblog.com/?p=72

您在上面看到的可能是因为您在同一个代码块中进行了两个测试。尝试评论一个,计时,然后评论另一个。此外,请确保您正在运行发布版本,而不是在调试器中。

于 2013-06-17T13:03:55.393 回答