集合类型的初始容量,例如字典、列表

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 初始化为容量 0。当添加第一项时,它重新初始化为容量 4。随后,每当达到容量时,容量就翻倍。

Dictionary 也初始化为容量为 0。但它使用完全不同的算法来增加容量:它总是将容量增加到素数。

【讨论】:

素数计算可能会处理散列冲突和探测输入位置。取决于内部机制,如果它们在每个散列中只存储一个值,那么它们需要辅助存储位置。如果您不使用素数,那么您可能会找到无法插入的哈希。 字典 使用链接。素数表大小弥补了较差的散列函数。好的散列函数产生随机分布;现代哈希表中使用了两种表大小的幂(.net 哈希表基于 Java 哈希表,该哈希表也使用素数,因为在哈希函数较差的时代,这是一种古老的做法)。由于 Microsoft 没有提供内置的哈希组合方法,因此许多自制的哈希函数会产生较差的分布,因此质数选择有时会进行补偿——直到哈希函数产生多个质数。 @FrankHileman “现代哈希表中使用了两种表大小的幂”。 Rust 使用 2 的幂,它的哈希表比 .NET 慢得多,因为它需要更复杂的哈希函数来避免冲突。 @John Harrop 使用高质量的哈希函数可以避免冲突。然后表大小成为一个自变量。【参考方案2】:

如果你知道尺寸,那就告诉它;在大多数“小”情况下的小优化,但对更大的集合很有用。我主要会担心这个问题,如果我投入“体面”的数据量,因为它可以避免分配、复制和收集多个数组。

大多数收藏确实使用加倍策略。

【讨论】:

【参考方案3】:

查看来源,List&lt;T&gt;Dictionary&lt;TKey, TValue&gt;的默认容量都是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 具有一致、更快的性能,尤其是当一个预先知道要添加到其中的项目数量。

所以故事的寓意是设置初始大小并不总能保证性能提升。

【讨论】:

以上是关于集合类型的初始容量,例如字典、列表的主要内容,如果未能解决你的问题,请参考以下文章

详解Python数据类型:字符串列表元组字典集合

详解Python数据类型:字符串列表元组字典集合

详解Python数据类型:字符串列表元组字典集合

python 数据类型 变量 列表 元组 字典 集合

python学习--数据类型详解(序列类型,集合,字典)

字符串元组列表字典集合-数据类型篇