集合类型的初始容量,例如字典、列表
Posted
技术标签:
【中文标题】集合类型的初始容量,例如字典、列表【英文标题】:Initial capacity of collection types, e.g. Dictionary, List 【发布时间】:2011-02-15 04:45:56 【问题描述】:.Net 中的某些集合类型具有可选的“初始容量”构造函数参数。例如:
Dictionary<string, string> something = new Dictionary<string,string>(20);
List<string> anything = new List<string>(50);
我似乎无法在 MSDN 上找到这些对象的默认初始容量。
如果我知道我只会在字典中存储 12 个左右的项目,那么将初始容量设置为 20 是否有意义?
我的理由是,假设容量像 StringBuilder 一样增长,每次容量都会增加一倍,并且每次重新分配的成本都很高,为什么不将大小预先设置为您知道可以保存数据的大小,有一些额外的空间以防万一?如果初始容量是 100,而我知道我只需要十几个左右,那么似乎剩下的内存是白分配的。
【问题讨论】:
【参考方案1】:如果没有记录默认值,原因可能是最佳初始容量是实现细节,并且在框架版本之间可能会发生变化。也就是说,您不应该编写假定某个默认值的代码。
构造函数具有容量的重载适用于您比类更清楚需要多少项目的情况。例如,如果您创建一个包含 50 个值的集合,并且知道这个数字永远不会增加,则可以将集合初始化为 50,这样如果默认容量较低,则不必调整大小。
也就是说,您可以使用 Reflector 确定默认值。例如,在 .NET 4.0(可能还有以前的版本)中,
一个 List
Dictionary
【讨论】:
素数计算可能会处理散列冲突和探测输入位置。取决于内部机制,如果它们在每个散列中只存储一个值,那么它们需要辅助存储位置。如果您不使用素数,那么您可能会找到无法插入的哈希。 字典如果你知道尺寸,那就告诉它;在大多数“小”情况下的小优化,但对更大的集合很有用。我主要会担心这个问题,如果我投入“体面”的数据量,因为它可以避免分配、复制和收集多个数组。
大多数收藏确实使用加倍策略。
【讨论】:
【参考方案3】:查看来源,List<T>
和Dictionary<TKey, TValue>
的默认容量都是0。
【讨论】:
在 .Net 4.5 中,附加容量实际上是 3。是的,默认构造函数调用容量值为 0 的重载构造函数,但是当构造函数调用 Initialize 方法时,大小设置为3. 字典的实际大小是通过调用 HashHelpers.GetPrime(capacity) 来确定的,它返回大于提供的容量的下一个素数。因此,在 .Net 4.5 中,字典的初始容量为 3。列表的默认容量为 0,但在将第一项添加到列表后容量变为 4。【参考方案4】:ConcurrentDictionary(当前)以及使用其构造函数设置初始大小的另一个问题是它的性能似乎受到了阻碍。
比如here's some example code and benchmarks我试过了。
我在我的机器上运行了代码并得到了类似的结果。
也就是说,当指定初始大小时,它不会在添加对象时增加 ConcurrentDictionary 的速度。从技术上讲,我认为它应该因为它不需要花费时间或资源来调整自身大小。
是的,它的运行速度可能不如普通字典快,但我仍然希望设置初始大小的 ConcurrentDictionary 比没有设置初始大小的 ConcurrentDictionary 具有一致、更快的性能,尤其是当一个预先知道要添加到其中的项目数量。
所以故事的寓意是设置初始大小并不总能保证性能提升。
【讨论】:
以上是关于集合类型的初始容量,例如字典、列表的主要内容,如果未能解决你的问题,请参考以下文章