Ale*_*i S 2 c# linq memory performance functional-programming
有时有必要在方法中间实际“评估” IEnumerable,因为它在多个查询中使用,并且编译器会发出警告(“可能的 IEnumerable 多重枚举”)
var skippedIds = objects.Where(x => x.State=="skip")
.Select(x => x.Id)
.Distinct();
var skippedLookup = skippedIds.ToLookup(x => x.FundId, _ => new { _.Id, _.Name});
if (skippedIds.Any()) // compiler warning
{
...
// other iterations over skippedIds, etc.
}
Run Code Online (Sandbox Code Playgroud)
我曾经做过:
var skippedIds = objects.Where(x => x.State=="skip")
.Select(x => x.Id)
.Distinct()
.ToList();
...
Run Code Online (Sandbox Code Playgroud)
但想知道是否有更好的选择。上面的代码List<T>在堆上创建对象,我猜这是在方法内死亡的临时变量的上下文中不必要的 GC 负担。我现在正在使用库ToImmutableArray()自带的System.Collections.Immutable。这不仅创建了堆栈分配的对象(不是真的,感谢评论者),而且还将“不可变”语义附加到我的代码中,我认为这是一个很好的函数式实践。
但对性能有什么影响呢?“具体化”在方法内本地多个位置使用的临时子查询结果的最佳方式是什么?
将其具体化到内存中对性能的影响是:
ToImmutableArray()大约会像ToArray()只ImmutableArray包装内置数组类型并删除突变选项一样快。Gen 0到Gen 1并在没有太多成本的情况下被收集。但显然,分配的大对象越多,触发集合的可能性就越大。您可以使用language-extSeq<A>中的类型(披露:我是作者)。它被设计为“更好的可枚举”,因为它只会一次性消耗每个项目,并且像.IEnumerable<A>IEnumerable<A>
所以,你可以这样做:
var skippedIds = objects.Where(x => x.State=="skip")
.Select(x => x.Id)
.Distinct()
.ToSeq();
Run Code Online (Sandbox Code Playgroud)
显然,这个世界上没有免费的东西,而代价是Seq<A>:
但好处是你只吃你需要的东西,而且只吃一次。就我个人而言,我希望限制您的查询和使用ToImmutableArray(),从数据库中获取少于您需要的数据将始终是首选方法。
| 归档时间: |
|
| 查看次数: |
894 次 |
| 最近记录: |