大家好
在下面的代码中
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));
}
根据我的理解,第二种方法应该更快,因为它迭代每个项目一次,而第一种方法运行两次:
但是在内部,编译器可能会将第一种方法转换为第二种方法,并且它们将具有相同的性能。
有什么建议或想法吗?
我可以按照建议进行分析,但我想了解编译器级别发生了什么,如果代码行与编译器相同,或者编译器会按字面意思对待它。
我刚刚运行了代码,第二个运行得更快:
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
你在没有衡量的情况下反对
.Where()
。 两种方法之间的真正区别在于.ToList()
。
第三种方法:
foreach(Person x in data.Where(x => x.Age > 40))
{
x.Age++;
}
我相信第一个会因为
ToList()
而变慢。 创建新的数据结构必须相对缓慢。
将代码粘贴到 LinqPad (www.linqpad.net) 中并计时。或者您可以检查生成的 IL 代码以查看编译器如何处理它。
如果您对编译器如何处理这两个表达式感兴趣,为什么不分别编译它们,然后使用 ildasm 工具(与 Visual Studio 捆绑)查看生成的代码?