C# 从IEnumerable初始化字典最有效的方法是什么?

C# 从IEnumerable初始化字典最有效的方法是什么?,c#,performance,dictionary,C#,Performance,Dictionary,我需要维护由整数唯一键控的数据库对象的缓存。一个查询传递一个IEnumerable MyEntity实例,该实例使用一个int主键和结果,我希望尽快初始化Dictionary实例,因为这个查询可以返回几十万行 从IEnumerable初始化Dictionary实例最有效的方法是什么 简言之,我想知道是否有更有效的方法: IEnumerable<MyEntity> entities = DoSomeQuery(); var cache = new Dictionary<int,

我需要维护由整数唯一键控的数据库对象的缓存。一个查询传递一个IEnumerable MyEntity实例,该实例使用一个int主键和结果,我希望尽快初始化Dictionary实例,因为这个查询可以返回几十万行

从IEnumerable初始化Dictionary实例最有效的方法是什么

简言之,我想知道是否有更有效的方法:

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与第一个示例类似,因此可以假设性能完全相同,如果不是稍差的话。也许这就是我的答案。

你已经尽可能快了

如果您可以快速确定要添加的元素数量,那么将其作为容量传递给字典构造函数将通过防止内部调整大小操作而带来些许提升。ToDictionary的.NET核心版本可以做到这一点,而其他版本则不行

如果键相对紧凑,则可以根据范围而不是计数调整大小。例如,如果您的ID为{5,6,7,9,10,11},那么如果缺少8而不是6,那么将值的数量调整为7将是有益的。事实上,这在这里没有什么区别,因为效果只会在比这更大的场景中出现。虽然效果很小,但如果你要浪费大量内存,那么不值得这么做。例如,在300容量的字典中存储{8307}绝对不值得!这样做的好处是增加了一个键被散列到某个元素的频率,该元素在内部大小(因此内部散列减少量)小于完成所有元素的添加时不会与另一个元素发生冲突

如果它们是紧密打包的,但您无法预测其大小,那么按顺序存储它们会有好处,因为随着内部存储的增长,字典通常会希望使用未使用的精简哈希代码存储某些内容。不过,这样做的好处比在内存中进行排序的成本要小,而且无论如何都需要查找元素的数量,可以是显式的,也可以是在OrderBy操作中查找元素的数量,因此,只有有一种方法可以让您以较低的成本完成排序,这样做才有帮助。例如,某些Web服务要求提供某种排序标准,因此您最好提供id作为标准。大多数情况下,这是不适用的

这些点,特别是最后两个,都是微小的影响,很可能加起来无法衡量。即使是第一个,如果它不在一个具有廉价计数或长度操作的源中,那么它也将小于获取计数的成本


foreach本身也许可以通过在适用时替换为索引来改进,但有时情况更糟。在某些具体类型的源上,它也会做得更好,例如T[]数组上的foreach比列表上的foreach好,IEnumerable上的foreach好,但这意味着在层之间公开实现细节,这几乎不值得,特别是因为许多集合类型都没有任何好处。

您已经尽可能快了

如果您可以快速确定要添加的元素数量,那么将其作为容量传递给字典构造函数将通过防止内部调整大小操作而带来些许提升。ToDictionary的.NET核心版本可以做到这一点,而其他版本则不行

如果键相对紧凑,则可以根据范围而不是计数调整大小。例如,如果您的ID为{5,6,7,9,10,11},那么如果缺少8而不是6,那么将值的数量调整为7将是有益的。事实上,这在这里没有什么区别,因为效果只会在比这更大的场景中出现。虽然效果很小,但如果你要浪费大量内存,那么不值得这么做。例如,在300容量的字典中存储{8307}绝对不值得!这样做的好处是增加了一个键被散列到某个元素的频率,该元素在内部大小(因此内部散列减少量)小于完成所有元素的添加时不会与另一个元素发生冲突

如果它们是紧密打包的,但您无法预测其大小,那么按顺序存储它们会有好处,因为随着内部存储的增长,字典通常会希望使用未使用的精简哈希代码存储某些内容。不过,这样做的好处将小于在内存中进行排序的成本,这将需要查找数字 无论是显式的还是在OrderBy操作中,元素的排序都是有效的,因此只有有一种方法可以让您以低廉的成本完成排序时,它才有帮助。例如,某些Web服务要求提供某种排序标准,因此您最好提供id作为标准。大多数情况下,这是不适用的

这些点,特别是最后两个,都是微小的影响,很可能加起来无法衡量。即使是第一个,如果它不在一个具有廉价计数或长度操作的源中,那么它也将小于获取计数的成本


foreach本身也许可以通过在适用时替换为索引来改进,但有时情况更糟。它在某些具体类型的源代码上也表现得更好,即T[]数组上的foreach比列表上的foreach好,IEnumerable上的foreach好,但这意味着在层之间公开实现细节,这是不值得的,尤其是因为许多集合类型没有任何好处。

您知道字典扩展方法吗?可以提高性能的一个方法是在构造期间将枚举长度作为容量传递给字典。dictionary.Add包括检查键是否已经存在。如果您知道正在插入好的数据,则可以用cache[key]=value替换它。但是,不确定此操作对性能的影响-您需要对其进行测量。@Rob这会执行完全相同的检查,但它只是覆盖现有项,而不是引发异常。“性能没有任何提高。@重新考虑后得出结论-你是对的-因为它必须检查是否存在以处理碰撞,无论如何。您知道ToDictionary扩展方法吗?可以提高性能的一件事是在构造期间将枚举长度作为容量传递给字典。dictionary.Add包括检查键是否已存在。如果您知道正在插入好的数据,则可以用cache[key]=value替换它。但是,不确定此操作对性能的影响-您需要对其进行测量。@Rob这会执行完全相同的检查,但它只是覆盖现有项,而不是引发异常。“性能并没有任何提高。@经过再三考虑,您是对的,因为它必须检查是否存在以处理碰撞。非常感谢。”。你教给我的正是我想学的东西,还有一些。我当然从来没有打算花几个小时研究这个问题,就像你说的那样,这是不现实的。但我有一个我想知道。。。一瞬间,现在我不再怀疑了非常感谢你。你教给我的正是我想学的东西,还有一些。我当然从来没有打算花几个小时研究这个问题,就像你说的那样,这是不现实的。但我有一个我想知道。。。一瞬间,现在我不再怀疑了