I'm testing performance differences using various lambda expression syntaxes. If I have a simple method:
public IEnumerable<Item> GetItems(int point)
{
return this.items.Where(i => i.IsApplicableFor(point));
}
在这里,涉及到与point
参数相关的一些变量提升,因为从lambda的角度来看,它是一个自由变量。如果我将调用此方法一百万次,将其保持不变还是改变以提高性能?
我有哪些选项,哪些是可行的?据我所知,我必须摆脱自由变量,这样编译器就不必在每次调用此方法时创建闭合类并对其进行实例化。与非闭合版本相比,这种实例化通常需要相当长的时间。
问题是我想要设计一些 lambda写作指南 ,它们通常可以使用,因为似乎每次我写一个经常使用的lambda表达式时都会浪费一些时间。我必须手动测试它以确保其有效,因为我不知道要遵循哪些规则。
替代方法
& 示例控制台应用程序代码
我还编写了同一方法的另一个版本,它不需要任何变量提升(至少我认为不需要,但你们理解这个的人让我知道是否正确):
public IEnumerable<Item> GetItems(int point)
{
Func<int, Func<Item, bool>> buildPredicate = p => i => i.IsApplicableFor(p);
return this.items.Where(buildPredicate(point));
}
请查看此处的Gist。只需创建一个控制台应用程序,并将整个代码复制到namespace
块内的Program.cs
文件中即可。您会发现,尽管第二个示例不使用free variables,但它要慢得多。
一个反例
我想构建一些lambda最佳使用指南的原因是,我之前遇到过这个问题,令我惊讶的是,当使用predicate builder lambda表达式时,其中一个方法竟然运行得更快。
现在请解释一下,我完全迷失了,因为当我知道我的代码中有一些重度使用方法时,可能根本不会使用lambda。但我想避免这种情况,并深入了解其本质。
编辑
您的建议似乎无效
我尝试实现了一个自定义查找类,其内部类似于编译器对于free variable lambda所做的操作。但是,我实现了模拟类似情况的实例成员。以下是代码:
private int Point { get; set; }
private bool IsItemValid(Item item)
{
return item.IsApplicableFor(this.Point);
}
public IEnumerable<TItem> GetItems(int point)
{
this.Point = point;
return this.items.Where(this.IsItemValid);
}
有趣的是,这个版本与慢速版本一样慢。我不知道为什么,但它似乎除了快速版本以外什么也没做。它重复使用了相同的功能,因为这些附加成员是同一个对象实例的一部分。无论如何,我现在非常困惑!
我已经更新了Gist源代码,所以你可以自行测试。