49

.Net 中的某些集合类型具有可选的“初始容量”构造函数参数。例如:

Dictionary<string, string> something = new Dictionary<string,string>(20);

List<string> anything = new List<string>(50);

我似乎无法在 MSDN 上找到这些对象的默认初始容量。

如果我知道我只会在字典中存储 12 个左右的项目,那么将初始容量设置为 20 是否有意义?

我的理由是,假设容量像 StringBuilder 一样增长,每次容量都会增加一倍,并且每次重新分配都是昂贵的,为什么不将大小预先设置为您知道可以保存数据的大小,并增加一些额外的房间以防万一?如果初始容量是 100,并且我知道我只需要十几个左右,那么似乎该内存的其余部分是白分配的。

4

4 回答 4

82

如果未记录默认值,则原因很可能是最佳初始容量是一个实现细节,并且可能会在框架版本之间发生变化。也就是说,您不应该编写假定某个默认值的代码。

具有容量的构造函数重载适用于您比类更了解预期项目数量的情况。例如,如果您创建一个包含 50 个值的集合,并且知道这个数字永远不会增加,则可以将集合初始化为 50,这样如果默认容量较低,则不必调整大小。

也就是说,您可以使用 Reflector 确定默认值。例如,在 .NET 4.0(可能还有以前的版本)中,

  • 将 List<T> 初始化为容量 0。当添加第一项时,将其重新初始化为容量 4。随后,每当达到容量时,容量就会加倍。

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

于 2010-05-03T20:21:36.743 回答
12

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

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

于 2010-05-03T20:22:14.963 回答
9

检查源,两者的默认容量为List<T>0 Dictionary<TKey, TValue>

于 2010-05-03T20:22:01.233 回答
3

ConcurrentDictionary(当前)以及使用其构造函数设置初始大小的另一个问题是它的性能似乎受到了阻碍。

例如,这是我尝试过的一些示例代码和基准测试。

我在我的机器上运行代码并得到了类似的结果。

也就是说,当指定初始大小时,它不会在添加对象时增加 ConcurrentDictionary 的速度。从技术上讲,我认为它应该是因为它不需要花费时间或资源来调整自身大小。

是的,它的运行速度可能不如普通字典快,但我仍然希望设置初始大小的 ConcurrentDictionary 比没有设置初始大小的 ConcurrentDictionary 具有一致、更快的性能,尤其是在事先知道的情况下要添加到其中的项目数。

所以这个故事的寓意是设置初始大小并不总是保证性能改进。

于 2015-01-29T07:33:28.413 回答