【问题标题】:What is the most performant way to initialize a Dictionary from an IEnumerable?从 IEnumerable 初始化 Dictionary 的最高效方法是什么?
【发布时间】:2017-02-27 02:13:15
【问题描述】:

我需要维护一个数据库对象的缓存,这些对象是唯一键控的(按整数)。一个查询提供IEnumerable<MyEntity> 的实例(MyEntity 使用int 主键)和结果,我想尽快初始化Dictionary<int, MyEntity> 的实例,因为这个查询可以返回一些十万行。

IEnumerable<MyEntity> 初始化Dictionary<int, MyEntity> 实例的最高效方法是什么?

简而言之,我想知道是否有更高效的方法来做到这一点:

IEnumerable<MyEntity> entities = DoSomeQuery();

var cache = new Dictionary<int, MyEntity>();

foreach (var entity in entities)
    cache.Add(entity.Id, entity);

//or...

cache = entities.ToDictionary(e => e.Id);

当然,查询具有最大的潜在性能影响,但重要的是我尽可能为我的用例减少毫秒。

编辑

在此值得注意的是,.ToDictionary&lt;TKey, TElement&gt;literally runs a foreach loop 与第一个示例一样,因此可以假设性能会完全相同,即使不是稍微差一点。也许这就是我的答案。

【问题讨论】:

  • 你知道ToDictionary扩展方法吗?
  • 可以提高性能的一件事是在构造过程中将枚举的长度作为容量传递给字典。
  • dictionary.Add 包括检查密钥是否已经存在。如果您知道您正在插入好的数据,则可以将其替换为 cache[key] = value。但是,不确定这对性能的影响 - 您需要对其进行衡量。
  • @Rob 执行完全相同的检查,但它只是覆盖现有项目而不是引发异常。没有性能提升。
  • @reduckted 再想一想 - 你是对的 - 因为无论如何它必须检查是否存在来处理冲突。

标签: c# performance dictionary


【解决方案1】:

你的速度差不多了。

如果您可以快速确定要添加的元素数量,那么将其作为容量传递给 Dictionary 构造函数将通过防止内部调整大小操作(@987654322 的 .NET Core 版本@ 会这样做,其他版本不会)。

如果键相对紧凑,那么您可以从调整范围而不是计数中受益。例如。如果您有Ids 和{5, 6, 7, 9, 10, 11},那么将大小设置为7(如果缺少8 时您将拥有的值的数量)而不是6 将是有益的。(实际上,在这里没有区别,因为效果只在比这更大的集合中起作用)。虽然效果相当小,所以如果您要浪费大量内存,则不值得这样做(例如,绝对不值得将 {8, 307} 存储在 300 容量的字典中!好处来自增加密钥的频率在内部大小(以及因此内部哈希减少)小于您完成全部添加时的期间,被散列到不会与另一个元素发生冲突的东西。

如果它们排列紧密,但您无法预测其大小,那么将它们按顺序存储是有好处的,因为随着内部存储的增长,字典想要存储带有未使用的缩减哈希码。虽然好处将小于在内存中排序的成本(并且无论如何都需要明确地或在OrderBy 操作中找到元素的数量),因此只有在有一种方法可以完成排序时才有用你便宜。 (例如,某些 web 服务要求提供 某种 排序标准,因此您不妨将 id 作为标准。大多数情况下这不适用)。

这些点,尤其是最后两个点,虽然是微小的影响,但很可能不会产生任何可测量的结果。如果它不在具有廉价CountLength 操作的源中,即使第一个也将小于获取计数的成本。

foreach 本身也许可以通过用索引替换(如果适用)来改进,但有时情况会更糟。它也倾向于在一些具体类型的源上做得更好(即foreach on T[] array beats foreach on List&lt;T&gt; beats foreach on IEnumerable&lt;T&gt;)但这意味着暴露层之间的实现细节并且很少值得,特别是因为许多集合类型没有任何好处。

【讨论】:

  • 非常感谢。你教给我的正是我想要学习的东西,然后是一些。我当然从来没有打算花几个小时研究这个,就像你说的那样不切实际。但我有一个“我想知道......”的时刻,现在我不再想知道了。 :)
猜你喜欢
  • 1970-01-01
  • 2010-09-17
  • 1970-01-01
  • 2010-09-18
  • 2012-01-28
  • 2014-09-10
  • 2012-02-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多