【问题标题】:Which is fast : Query Syntax vs. Loops哪个快:查询语法与循环
【发布时间】:2011-01-20 19:23:06
【问题描述】:

以下代码提供了两种方法来生成总和小于 100 的整数对,并根据它们与 (0,0) 的距离以降序排列。

    //approach 1
    private static IEnumerable<Tuple<int,int>>  ProduceIndices3()
    {
        var storage = new List<Tuple<int, int>>();
        for (int x = 0; x < 100; x++)
        {
            for (int y = 0; y < 100; y++)
            {
                if (x + y < 100)
                    storage.Add(Tuple.Create(x, y));
            }
        }
        storage.Sort((p1,p2) =>
           (p2.Item1 * p2.Item1 + 
           p2.Item2 * p2.Item2).CompareTo(
           p1.Item1 * p1.Item1 +
           p1.Item2 * p1.Item2));
        return storage;
    }

    //approach 2
    private static IEnumerable<Tuple<int, int>> QueryIndices3()
    {
        return from x in Enumerable.Range(0, 100)
               from y in Enumerable.Range(0, 100)
               where x + y < 100
               orderby (x * x + y * y) descending
               select Tuple.Create(x, y);
    }

这段代码摘自Bill Wagner的Effective C#一书,Item 8。在整篇文章中,作者更多地关注代码的语法、紧凑性和可读性,但很少关注表演,几乎不讨论。

所以我基本上想知道,哪种方法更快?什么通常在性能上更好(一般而言):查询语法或手动循环?

请详细讨论它们,如果有的话提供参考。 :-)

【问题讨论】:

  • 查询必须在某个时候陷入循环,因此必须有一些开销,即使差异可以忽略不计。
  • 只是出于好奇,你能解释一下这个排序吗?:orderby (x * x + y * y) descending 我不明白它是如何工作的
  • 第二个会快很多,因为它除了构建查询之外什么都不做,在执行 ToList() 之后,您将能够比较;)
  • 注意:这是到 0 的距离

标签: c# performance loops code-readability linq-query-syntax


【解决方案1】:

分析是事实,但我的直觉是循环可能更快。重要的是,100 次中有 99 次的性能差异在宏伟的计划中并不重要。使用更易读的版本,当您以后需要维护它时,您未来的自己会感谢您。

【讨论】:

  • 补充一句,第二种方法,编译器可以更好地理解代码的目的,从而可以更合理地优化。也许现在,即使经过优化,第一种方法会运行得更快,但是,在不远的将来,我们可能会从第一种获得更好的性能。
  • 对于小型学习项目来说,分析可能有点矫枉过正。将数字从 100 增加到 1,000,000 真的很容易,只需用秒表测量时间差即可。
  • @Phil - 我会考虑分析,即使你没有使用花哨的工具来做。
【解决方案2】:

每个函数运行 1000 次:

for 循环:2623 毫秒 查询:2821 毫秒

看起来很合乎逻辑,因为第二个只是第一个的语法糖。但我会使用第二个,因为它的可读性。

【讨论】:

  • 出于好奇,当您对此进行分析时,您是否真的从第二个函数中枚举了查询(例如,使用 .ToList() 之类的?)
  • 做了 ToList,没有那个就花了大约 3ms ;)
【解决方案3】:

虽然这不能严格回答您的问题,但在性能方面我建议将 x+y 逻辑合并到迭代中,因此:

for (int x = 0; x < 100; x++)
    for (int y = 0; y < 100 - x; y++)
        storage.Add(Tuple.Create(x, y));

【讨论】:

  • 聪明,但它会“偏向”与其他函数的速度比较(需要更改:从 y in Enumerable.Range(0, 100-x))
  • 老实说,任何半体面的优化编译器都应该使这种变化可以忽略不计。
猜你喜欢
  • 1970-01-01
  • 2011-03-25
  • 1970-01-01
  • 2013-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-27
  • 2011-03-03
相关资源
最近更新 更多