【发布时间】:2014-12-10 14:59:44
【问题描述】:
将 4.5.1 与一个应用程序一起使用,该应用程序在服务器端通过多个 REST 请求同时对图表数据进行混洗。
使用 IQueryable 构建查询。例如,我最初有以下几点:
var query = ctx.Respondents
.Join(
ctx.Respondents,
other => other.RespondentId,
res => res.RespondentId,
(other, res) => new ChartJoin { Respondent = res, Occasion = null, BrandVisited = null, BrandInfo = null, Party = null, Item = null }
)
. // bunch of other joins filling out the ChartJoin
.Where(x => x.Respondent.status == 1)
. // more Where clauses dynamically applied
.GroupBy(x => new CommonGroupBy { Year = (int)x.Respondent.currentVisitYear, Month = (int)x.Respondent.currentVisitMonth })
.OrderBy(x => x.Key.Year)
.ThenBy(x => x.Key.Month)
.Select(x => new AverageEaterCheque
{
Year = x.Key.Year,
Month = x.Key.Month,
AverageCheque = (double)(x.Sum(m => m.BrandVisited.DOLLAR_TOTAL) / x.Sum(m => m.BrandVisited.NUM_PAID)),
Base = x.Count(),
Days = x.Select(m => m.Respondent.visitDate).Distinct().Count()
});
为了允许动态分组(通过客户端),GroupBy 是使用返回字典的 C# 表达式生成的。 Select 也必须使用表达式生成。上面的 Select 变成了这样:
public static Expression<Func<IGrouping<IDictionary<string, object>, ChartJoin>, AverageEaterCheque>> GetAverageEaterChequeSelector()
{
// x =>
var ParameterType = typeof(IGrouping<IDictionary<string, object>, ChartJoin>);
var parameter = Expression.Parameter(ParameterType);
// x => x.Sum(m => m.BrandVisited.DOLLAR_TOTAL) / x.Sum(m => m.BrandVisited.NUM_PAID)
var m = Expression.Parameter(typeof(ChartJoin), "m");
var mBrandVisited = Expression.PropertyOrField(m, "BrandVisited");
PropertyInfo DollarTotalPropertyInfo = typeof(BrandVisited).GetProperty("DOLLAR_TOTAL");
PropertyInfo NumPaidPropertyInfo = typeof(BrandVisited).GetProperty("NUM_PAID");
....
return a lambda...
}
当我在本地进行测试运行时,出现内存不足错误。然后我开始阅读 Totin 和其他 Lambda 编译的博客,一般来说,表达式树很昂贵。不知道它会破坏我的应用程序。而且我需要动态添加分组的能力,这导致我将表达式树用于 GroupBy 和 Select 子句。
想要一些关于如何在我的应用程序中追踪内存违规者的指示吗?已经看到有些人使用 dotMemory,但也可以使用一些实用技巧。很少有监控C#、DotNet的经验。
【问题讨论】:
-
我将首先检查您的 EF 查询返回的数据。这更有可能是内存猪而不是表达式。
-
您显示的代码根本没有使用您正在构建的表达式。我们怎么能告诉您您没有向我们展示的代码有什么问题?
-
@Servy,问题显示了硬编码的 GroupBy 和 Select 子句编写为内联 lambda,然后是使用表达式编写 Select 子句的简短示例。那次切换是我注意到内存问题的时候。
-
@user1620220,我下载了 dotMemory 并进行了分析。看起来 String 和 Dictionary 对象正在消耗第 2 代。也许 Dictionary(从 GroupBy 传递到 Select)不是“动态”结构的好选择?
-
第 2 代的利用率为 99%。必须阅读 C# 堆。
标签: c# performance linq lambda expression-trees