修复 c 中可枚举 lambda 中的闭包分配#

Fix closure allocations in enumerable lambdas in c#

提问人:Raptor 提问时间:6/24/2022 最后编辑:Raptor 更新时间:6/24/2022 访问量:307

问:

我在 Rider 中有 DPA 插件,它向我展示了 lambda 中的一些闭包分配。

我知道什么是封闭以及为什么会有封闭。我知道为什么被创造。c_DisplayClassxx

但我的问题是 - 如何更改代码来修复它?

大多数情况下,我的问题出在可枚举中,,...我不知道如何编写谓词来避免闭包分配。WhereFirstOrDefault

下面是一个示例 - 闭包获取所有 5 个参数,它消耗大量内存。

    public IList<RequirementMappingRule> FindItems(ProductFilterMap productMapItem, 
        RuleProviderContext context)
    {
        var financialCompanyCode = productMapItem.Product.Product.FinancialCompanyCode;
        var parentRiskCode = productMapItem.ParentRiskCode;
        var riskCode = productMapItem.Risk.Risk.Code;

        var ruleCandidates = Items.Where(r =>
                (r.CompanyCode == financialCompanyCode || r.CompanyCode == "*")
                && r.ParentRiskCode == parentRiskCode
                && (string.IsNullOrWhiteSpace(r.RiskCode) || r.RiskCode == riskCode)
                && r.IsValidByRiskValue(productMapItem, context))
            .ToList();
         
        // etc. ...
}

更新:只是为了澄清我的问题 - 闭包捕获 financialCompanyCode、parentRiskCode 等。我想知道是否有任何模式可以避免完全闭合。我认为使用和参数总是以闭包和生成结束,所以修复它的唯一方法是不使用和使用或获取项目。WhereDisplayClassWhereforeachfor

我说得对吗?

C# 闭包 堆内存

评论

0赞 Charlieface 6/24/2022
r.IsValidByRiskValue(productMapItem, context)看看这个函数,也许可以改变它,这样你就不需要传递整个上下文了
0赞 Raptor 6/24/2022
是的,这是功能,但并不重要。Closure 捕获 financialCompanyCode、parentRiskCode 等。我想知道是否有任何模式可以避免完全闭合。我认为使用 and 参数总是以闭包和生成 DisplayClass 结尾,所以修复 ot 的唯一方法是不要使用 Where ans use .Whereforeach
1赞 Charlieface 6/24/2022
关闭本身并不一定是有问题的,这取决于它坚持了多少。此外,如果您立即执行 lambda 并且不坚持它,那么它应该不是问题。你为什么认为“它消耗了大量的内存”,你这种断言的依据是什么?您是否运行过内存分析器,它显示了一个挂在该 lambda 上的大对象图?
0赞 Raptor 6/24/2022
这个函数是所以被多次调用的一部分。每个调用都以 DisplayClass 的新实例结束,并且由于 中使用的参数,内存被分配(设计不好,例如上下文不是简单的值等),并且不会立即处置。所以我需要重写代码,是的,但只是想知道是否总是会有闭包或可以在没有闭包的情况下编写 Where。hot pathWhere
1赞 Charlieface 6/24/2022
LINQ 在非常热的路径中并不是那么好,正是因为闭合问题。不,在使用 LINQ 时无法重写它,因为您需要某种方法来捕获该数据。在使用 LINQ 时,唯一的选择是使用重写器作为生成的一部分,请参见 mattwarren.org/2016/09/29/Optimising-LINQ

答: 暂无答案