Joh*_*ger 5 c# performance garbage-collection string-comparison
我有一个名为 SelectedSections 的属性,它是从部分集合中分配的。每个部分都包含一个 BidItems 集合,其中包含 1,000 多个项目。当我选择一个部分时,我需要使用一组已过滤的项目来刷新视图数据绑定到的项目集合。
public Section SelectedSection
{
get
{
return selectedSection;
}
set
{
this.SetPropertyByReference(ref this.selectedSection, value);
if (value != null)
{
this.BidItems = value.BidItems
.Where(item =>
!item.Description.ToLower().Contains("flagger") ||
!item.Description.ToLower().Contains("civilian flagger") ||
!item.Description.ToLower().Contains("law enforcement"))
.ToList();
}
this.MptPayment.EditedItem.DiaryPayItem.Section = value;
}
}
Run Code Online (Sandbox Code Playgroud)
我必须过滤掉大约十几个不同类型的项目(为了清楚起见,我只显示了 3 个)。在我的Where子句中,在检查集合是否包含我要过滤掉的内容之前,我将所有内容都转换为小写。
我意识到这会产生大量垃圾,因为集合中 1,000 多个项目中的每一个都会为小写Description内容创建一个新字符串。我的问题是,对集合中的每个项目执行十几次会比我只检查所有已知的变体更昂贵吗?忽略我可能会错过一个变化的事实,因为我对哪个更快的理论更感兴趣。
上面的列表是所有已知的变体。我想知道哪条路线更贵。迭代集合来检查每个已知条件将足够快,而不会产生这么多垃圾的开销。要么对每个项目/描述枚举一次以上,以便找到全部,要么对每个项目/描述枚举一次,同时在堆上创建垃圾字符串,然后进行 GC。
请注意,当用户执行其工作时,此属性可能会重新设置数十次。因此将执行大量(数万次)字符串比较。
我意识到相对于应用程序的其他部分来说,这是一个便宜的操作;我想了解更多信息以进行自我教育,而不是担心实际应用程序中的性能下降。
ToLower()在大型集合上会产生不必要的 GC 压力。相反,IndexOf >= 0使用StringConparison.OrdinalIgnoreCase:
this.BidItems = value.BidItems
.Where(item =>
!(item.Description.IndexOf("flagger", StringComparison.OrdinalIgnoreCase) >= 0) ||
!(item.Description.IndexOf("civilian flagger", StringComparison.OrdinalIgnoreCase) >= 0) ||
!(item.Description.IndexOf("law enforcement", StringComparison.OrdinalIgnoreCase) >= 0))
.ToList();
Run Code Online (Sandbox Code Playgroud)
一个个人故事 - 我在分析我们的应用程序时发现负责 XML 反序列化的方法正在发出大量字符串,导致我们的应用程序每次运行发出大约 1.5GB 的字符串。这种方法是我们的热门方法。这最终成为一名程序员ToLower在每次解析迭代中进行的操作。通过删除该调用,我最终在每次运行中节省了超过 1GB 的分配。
随着您的集合变得越来越大,您会发现这会导致越来越多的 GC 压力。如果你能避免它,那就这样做。