代码之家  ›  专栏  ›  技术社区  ›  Neil N HLGEM

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

  •  34
  • Neil N HLGEM  · 技术社区  · 16 年前

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

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

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

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

    我的理由是,假设容量像StringBuilder一样增长,每次容量被命中时都会翻倍,而且每次重新分配都很昂贵,为什么不将大小预先设置为您知道可以保存数据的大小,并留一些额外的空间以备万一呢?如果初始容量是100,并且我知道我只需要十几个,那么似乎该内存的其余部分是无偿分配的。

    4 回复  |  直到 11 年前
        1
  •  69
  •   Neil N HLGEM    14 年前

    如果没有记录默认值,原因很可能是最佳初始通行能力是 实施详细信息 以及框架版本之间的变化。也就是说,您不应该编写假定某个默认值的代码。

    建造师 容量过载是为了更好地了解 而不是类,需要多少项。例如,如果您创建了一个50个值的集合,并且知道这个数字永远不会增加,则可以用50的容量初始化集合,因此如果默认容量较低,则不必调整大小。

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

    • 列表的初始化容量为0。添加第一个项目时,它将重新初始化为4个容量。随后,只要达到容量,容量就会翻倍。

    • 字典的首字母大小也为0。但是它使用了一种完全不同的算法来增加容量:它总是将容量增加到素数。

        2
  •  9
  •   SLaks    16 年前

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

        3
  •  9
  •   Marc Gravell    16 年前

    如果你知道它的大小,那就告诉它;在大多数“小”的情况下,这是一个小的优化,但对更大的收藏有用。我会的 主要地 如果我将“相当”数量的数据放入其中,就要担心这个问题,因为这样可以避免分配、复制和收集多个数组。

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

        4
  •  2
  •   Thrawn Wannabe    11 年前

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

    例如, here's some example code and benchmarks 我试过了。

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

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

    是的,它的运行速度可能不如普通字典快,但我仍然希望具有初始大小集的ConcurrentDictionary比没有初始大小集的ConcurrentDictionary具有一致、更快的性能,特别是当提前知道将被添加到其中。

    所以这个故事的寓意是设定初始规模并不总是保证性能的提高。