C#linqorderby和其他带有foreach的语句,是否存在性能差异
本文关键字:是否 存在 性能 语句 其他 foreach C#linqorderby | 更新日期: 2023-09-27 18:27:03
我正在对实体框架、集合和其他方面进行大量编程,并根据操作确定条件和顺序。我问自己这个问题已经有一段时间了,但一直没能弄清楚。
假设我有以下两段代码;
示例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,然后在集合上迭代,其中第二个例子在我们要迭代它的时候具有order by。。性能上有什么不同(如果有的话)?这两种方法中的一种比另一种好吗?和where条件(带连接的简单条件和复杂条件)一样,有什么显著的区别吗?
两者之间没有区别。。
代码-
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);
您的第一个查询相当于
... = letters.OrderBy(letter => letter).Select(letter => letter);
您的第二个查询是
... in letter.OrderBy(l => l)) {
两个查询几乎相同,只有第一个查询有一个额外的.Select(...)
调用,您可以在其中选择给定的输入,所以这是毫无意义的。C#编译器可能会删除调用,但您必须查看生成的IL才能知道这一点。
此外,您的第一个语句不执行查询。.OrderBy(...)
和大多数linq语句都是查询定义。这意味着您对.OrderBy(...)
的调用实际上并没有执行,这是一个直到您迭代结果才会得到回答的问题。因此,在这两个版本中,当foreach (... in <collection>)
访问它要迭代的集合时,都会执行查询。
结论:性能差异会很小,以至于你必须非常努力地发现任何真正的差异。当然,这是我谦虚的猜测。
我能看到的唯一区别是,在第一个代码中,Iterator
在foreach
之前创建(未执行),并且您将其存储在本地变量中。在第二个代码中,foreach
直接调用迭代器上的GetEnumarator
方法,而不是本地变量。但这当然不会对性能产生任何影响。除此之外,由于可读性,我更喜欢第二个。