C#linq order by和foreach的其他语句,是否有性能差异?

时间:2014-10-20 07:34:22

标签: c# performance linq query-performance

我使用实体框架,集合以及那里的usting where-conditions和order by actions来进行很多编程。我已经问了一段时间,但从来没有弄明白。

让我说下面有两段代码;

示例1:

// An unsorted string array.
string[] letters = { "d", "c", "a", "b" };
// Use LINQ query syntax to sort the array alphabetically.
var sorted = from letter in letters
         orderby letter
         select letter;

// Loop with the foreach keyword.
foreach (string value in sorted)
{
    Console.WriteLine(value);
}

示例2:

// An unsorted string array.
string[] letters = { "d", "c", "a", "b" };

// Loop with the foreach keyword.
foreach (string val in letters.OrderBy(l => l))
{
    console.writeline(val)
}

第一个示例首先对结果集执行一个order by,然后在我们要迭代它的那一刻迭代第二个具有顺序的集合。现在真正的问题我一直想知道......性能有什么不同(如果有的话)?并且两种方法中的一种比另一种更好吗?与条件(具有连接的简单和复杂条件)相同,是否存在显着差异?

3 个答案:

答案 0 :(得分:4)

这两者没有区别..

代码 -

static void Main(string[] args)
{
    string[] letters = { "d", "c", "a", "b" };
    // Use LINQ query syntax to sort the array alphabetically.
    var sorted = from letter in letters
                    orderby letter
                    select letter;

    // Loop with the foreach keyword.
    foreach (string value in sorted)
    {
        Console.WriteLine(value);
    }

    foreach (string val in letters.OrderBy(letter => letter))
    {
        Console.WriteLine(val);
    }
}

生成的代码 -

private static void Main(string[] args)
{
  string[] strArray1 = new string[4]
  {
    "d",
    "c",
    "a",
    "b"
  };
  string[] strArray2 = strArray1;
  if (Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate2 == null)
  {
    // ISSUE: method pointer
    Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate2 = new Func<string, string>((object) null, __methodptr(\u003CMain\u003Eb__0));
  }
  Func<string, string> keySelector1 = Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate2;
  foreach (string str in (IEnumerable<string>) Enumerable.OrderBy<string, string>((IEnumerable<string>) strArray2, keySelector1))
    Console.WriteLine(str);
  string[] strArray3 = strArray1;
  if (Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate3 == null)
  {
    // ISSUE: method pointer
    Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate3 = new Func<string, string>((object) null, __methodptr(\u003CMain\u003Eb__1));
  }
  Func<string, string> keySelector2 = Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate3;
  foreach (string str in (IEnumerable<string>) Enumerable.OrderBy<string, string>((IEnumerable<string>) strArray3, keySelector2))
    Console.WriteLine(str);
}

[CompilerGenerated]
private static string \u003CMain\u003Eb__0(string letter)
{
  return letter;
}

[CompilerGenerated]
private static string \u003CMain\u003Eb__1(string letter)
{
  return letter;
}

修改 这是一个有趣的变化我试图尝试..在上面的情况下,对于查询表达式,编译器足够聪明,可以优化Select ..但是,如果,在第二个变体,我们在明确的Select。这有点不足为奇,但编译器仍然没有优化显式.Select(与查询表达式中的显式Select - 编译器的要求)。

代码 -

    foreach (string val in letters.OrderBy(letter => letter).Select(letter => letter))
    {
        Console.WriteLine(val);
    }

生成的代码 -

  string[] strArray4 = strArray1;
  if (Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate6 == null)
  {
    // ISSUE: method pointer
    Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate6 = new Func<string, string>((object) null, __methodptr(\u003CMain\u003Eb__2));
  }
  Func<string, string> keySelector3 = Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate6;
  IOrderedEnumerable<string> orderedEnumerable = Enumerable.OrderBy<string, string>((IEnumerable<string>) strArray4, keySelector3);
  if (Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate7 == null)
  {
    // ISSUE: method pointer
    Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate7 = new Func<string, string>((object) null, __methodptr(\u003CMain\u003Eb__3));
  }
  Func<string, string> selector = Program.CS\u0024\u003C\u003E9__CachedAnonymousMethodDelegate7;
  foreach (string str in Enumerable.Select<string, string>((IEnumerable<string>) orderedEnumerable, selector))
    Console.WriteLine(str);

答案 1 :(得分:2)

您的第一个查询等同于

... = letters.OrderBy(letter => letter).Select(letter => letter);

你的第二个问题是

... in letter.OrderBy(l => l)) {

两个查询几乎完全相同,只有第一个查询有一个额外的.Select(...)调用,你选择给定的输入,所以这是毫无意义的。 C#编译器可能会删除该调用,但您必须查看生成的IL才能知道这一点。

此外,您的第一个语句不会执行查询。 .OrderBy(...)和大多数linq语句都是查询定义。这意味着您对.OrderBy(...)的调用实际上并未执行,而这个问题在您对结果进行迭代之前无法解答。因此,在您的两个版本中,当foreach (... in <collection>)访问要迭代的集合时,将执行查询。

结论:性能差异很小,你必须非常努力地发现任何真正的差异。当然,这是我的谦虚猜测。

答案 2 :(得分:0)

我能看到的唯一区别是,Iteratorforeach之前创建(未执行)的第一个代码中,并将它存储在局部变量中。在第二个代码中foreach直接调用迭代器上的GetEnumarator方法而不是局部变量。但是对于性能而言,这并没有任何区别。除此之外,由于可读性,我更倾向于第二种。