【问题标题】:Which LINQ expression is faster哪个 LINQ 表达式更快
【发布时间】:2011-01-06 18:38:08
【问题描述】:

大家好

在下面的代码中

public class Person
{
    public string Name { get; set; }
    public uint Age { get; set; }

    public Person(string name, uint age)
    {
        Name = name;
        Age = age;
    }
}

void Main()
{
    var data = new List<Person>{ new Person("Bill Gates", 55), 
                                new Person("Steve Ballmer", 54), 
                                new Person("Steve Jobs", 55), 
                                new Person("Scott Gu", 35)};

    // 1st approach
    data.Where (x => x.Age > 40).ToList().ForEach(x => x.Age++);

    // 2nd approach
    data.ForEach(x => 
                    {
                        if (x.Age > 40)
                            x.Age++;
                    });

    data.ForEach(x => Console.WriteLine(x));    
}

在我的理解中,第二种方法应该更快,因为它遍历每个项目一次,第一种方法运行 2 次:

  1. Where 子句
  2. ForEach 在 where 子句中的项目子集上。

但是在内部,编译器可能会将第一种方法转换为第二种方法,并且它们将具有相同的性能。

有什么建议或想法吗?

我可以按照建议进行分析,但我想了解编译器级别的情况,如果代码行与编译器相同,或者编译器会按字面意思对待它。

提前感谢您的帮助。

【问题讨论】:

  • profiling...用秒表进行测量,看看哪个更快
  • 你能不能只计时看看哪个更快?
  • ps。从技术上讲,第二种方法(列表中的 ForEach)不是 Linq,因为它是 List 类上的直接方法,将委托作为参数。
  • 一个比我聪明得多的人曾经说过“你已经用两种方式编写了它,自己测试一下,确定是否存在相关的、可证明的差异。”
  • 如果您为IEnumerable 创建了一个ForEach 扩展方法,那么您可以删除ToList,它们将是相同的。

标签: c# .net linq performance compiler-construction


【解决方案1】:

我刚跑了代码,第二个跑得更快:

static void T3()
        {
            var data = new List<Person>{ new Person("Bill Gates", 55), 
                                new Person("Steve Ballmer", 54), 
                                new Person("Steve Jobs", 55), 
                                new Person("Scott Gu", 35)};

            System.Diagnostics.Stopwatch s1 = new System.Diagnostics.Stopwatch();

            s1.Start();
            // 1st approach
            data.Where(x => x.Age > 40).ToList().ForEach(x => x.Age++);
            s1.Stop();

            System.Diagnostics.Stopwatch s2 = new System.Diagnostics.Stopwatch();

            s2.Start();
            // 2nd approach
            data.ForEach(x =>
            {
                if (x.Age > 40)
                    x.Age++;
            });
            s2.Stop();

            Console.Write("s1: " + s1.ElapsedTicks + " S2:" + s2.ElapsedTicks);
            data.ForEach(x => Console.WriteLine(x));
        }

这是意料之中的,因为第二个不需要转换为列表然后运行 ​​foreach 方法。

结果:s1: 1192 S2:255

【讨论】:

  • 您费心运行此测试,但没有向我们展示结果? :)
【解决方案2】:

你反对.Where() 没有测量。这两种方法的真正区别在于.ToList()

第三种方法:

foreach(Person x in data.Where(x => x.Age > 40))
{
  x.Age++; 
}

【讨论】:

    【解决方案3】:

    我相信第一个会因为ToList()而变慢。创建新的数据结构必须相对较慢。

    【讨论】:

      【解决方案4】:

      将代码粘贴到 LinqPad (www.linqpad.net) 并计时。或者您可以检查生成的 IL 代码以了解编译器如何处理它。

      【讨论】:

      • 我可以,但就像我说的,我对编译器如何看待这两个表达式更感兴趣。既然它们是相同的,编译器是否应该优化并将其作为第二种方法?
      • @Vlad - 将其粘贴到 LinqPad 中并检查生成的 IL 代码。
      【解决方案5】:

      如果您对编译器如何处理这两个表达式感兴趣,为什么不分别编译,然后使用 ildasm 工具(与 Visual Studio 捆绑)查看生成的代码?

      【讨论】:

        猜你喜欢
        • 2011-11-22
        • 1970-01-01
        • 2021-12-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多