【问题标题】:LINQ vs foreach vs for performance test resultsLINQ vs foreach vs 性能测试结果
【发布时间】:2014-05-16 02:01:41
【问题描述】:

有人能解释一下这些结果吗? 我知道有重复的问题,但我还没有找到一个与我的结果得出相同结论的问题:o

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SpeedTest
{
    class Person
    {    
        public Person(string name)
        {
            this.Name = name;
        }

        public string Name { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var people = new List<Person>();
            AddTwins("FRANCISCO", people);
            var stopwatch = new Stopwatch();

            string name = "OCSICNARF";

            long linqTime = 0L;
            long foreachTime = 0L;
            long forTime = 0L;

            stopwatch.Start();
            Person person0;
            var result = from person in people
                         where person.Name == name
                         select person;
            person0 = result.First();
            linqTime = stopwatch.ElapsedMilliseconds;
            stopwatch.Restart();
            Person person1;
            foreach (Person p in people)
            {
                if (p.Name == name)
                {
                    person1 = p;
                    break;
                }
            }
            foreachTime = stopwatch.ElapsedMilliseconds;
            stopwatch.Restart();
            Person person2;
            for (int i = 0; i < people.Count; i++)
            {
                if (people[i].Name == name)
                {
                    person2 = people[i];
                    break;
                }
            }
            forTime = stopwatch.ElapsedMilliseconds;
            stopwatch.Stop();

            Console.WriteLine(string.Format("LINQ took {0}ms", linqTime));
            Console.WriteLine(string.Format("FOREACH took {0}ms", foreachTime));
            Console.WriteLine(string.Format("FOR took {0}ms", forTime));
        }

        static void AddTwins(string name, List<Person> people)
        {
            AddTwins(people, name, "");
        }

        private static void AddTwins(List<Person> people, string choices, string chosen)
        {
            if (choices.Length == 0)
            {
                people.Add(new Person(chosen));
            }
            else
            {
                for (int i = 0; i < choices.Length; i++)
                {
                    // choose
                    char c = choices[i];
                    string choose1 = choices.Substring(0, i);
                    string choose2 = choices.Substring(i + 1);
                    choices = choose1 + choose2;

                    // explore
                    AddTwins(people, choices, chosen + c);

                    // Unchoose
                    string unchoose1 = choices.Substring(0, i);
                    string unchoose2 = choices.Substring(i);
                    choices = unchoose1 + c + unchoose2;
                }
            }
        }
    }
}

【问题讨论】:

标签: c# performance linq for-loop foreach


【解决方案1】:

您永远不会执行LINQ 查询,您只需创建它。您应该使用ToListToArray 方法来强制迭代,可能不会得到不同的结果,因为LINQ 也使用foreach 循环。

编辑LINQ 需要更多时间,因为您正在遍历所有项目。但是在其他两个循环中,一旦找到匹配项,您就会打破循环。尝试使用FirstOrDefault 而不是Where,您应该会得到相同(或相似)的结果。

people.FirstOrDefault(p => p.Name == name);

【讨论】:

  • 我的错,我刚刚意识到这一点,看看新的结果/代码。
【解决方案2】:

linq 不花时间,因为查询从未真正评估

Linq is lazy 对于大多数操作,在有人开始枚举结果之前它实际上不会做任何事情。

如果你添加了

result.Count(); // add this line, query will be evaluated
linqTime = stopwatch.ElapsedMilliseconds;
stopwatch.Restart();

那么我很确定你会得到一个非零的 linq 结果。

【讨论】:

  • 是的,我注意到了,但你们对我来说太快了。查看新结果。如果 LINQ 查询应该像 foreach 循环一样有一个 foreach,为什么它会更慢?
  • 如果你查看它的生成代码,foreach 可能非常“平坦”,其中生成的代码可能有一些额外的方法调用可以进入/从 foreach 中取出,然后 yield return 之类的东西。
【解决方案3】:

显然,Sum 必须在堆上存储列表枚举器的装箱实例,并使用该堆对象来迭代列表。内联 foreach 和 for 循环都避免了这种情况;前者是因为 List 的公共 GetEnumerator 方法返回一个值类型。如果您在 IEnumerable&lt;Person&gt; 变量中存储对人员的引用,则 foreach 循环需要更长的时间才能获得结果。

此外,linq 必须为 where 迭代器和传递给它的委托创建对象,并且它会进行更多的 null 检查,以便在任何参数为 null 时抛出信息异常。这可以解释 linq 代码所需的其余额外时间。

【讨论】: