2010-05-03 32 views
29

.Net中的某些集合類型具有可選的「初始容量」構造函數參數。例如:集合類型的初始容量,例如詞典,列表

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

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

我似乎無法找到MSDN上這些對象的默認初始容量。

如果我知道我只會在一本字典中存儲12個左右的項目,那麼將初始容量設置爲20之類沒有意義嗎?

我的推理是,假設容量增長就像它爲StringBuilder做的那樣,每當容量被擊中時會翻倍,並且每次重新分配都很昂貴,爲什麼不預先將大小設置爲你知道將容納你的數據的東西,有一些額外的空間以防萬一?如果最初的容量是100,而且我知道我只需要十幾個,那麼這個內存的其餘部分似乎就沒有分配。

回答

60

如果沒有記錄默認值,原因可能是最佳初始容量是實施細節並且可能會在框架版本之間發生變化。也就是說,您不應該編寫假定某個默認值的代碼。

帶有容量的構造函數重載對於您比其他類知道更好的的情況,比預期的項數目多。例如,如果創建一個包含50個值的集合並知道此數字永遠不會增加,則可以將容量初始化爲50,因此如果默認容量較低,則無需調整大小。

也就是說,您可以使用Reflector確定默認值。例如,在.NET 4.0(也可能以前的版本爲好),

  • 列表<Ť>與0的容量初始化當加入的第一項,它被重新初始化的容量4.隨後,只要達到容量,容量就會翻倍。

  • a詞典<T>也初始化爲容量爲0。但它使用完全不同的算法來增加容量:它始終增加素數的容量。

+6

質數計算可能會處理散列衝突和探測輸入位置。根據內部機制,如果他們只在每個散列處存儲一個值,則他們需要輔助存儲位置。如果您不使用素數,那麼您可能會發現可能無法插入的散列。 – Matt 2010-05-04 03:40:56

+5

詞典使用鏈接。素數表格大小彌補了較差的散列函數。好的散列函數產生隨機分佈;現代哈希表中使用了兩種表大小的功能(.net哈希表基於Java哈希表,該哈希表也使用素數,因爲在哈希函數較差的日子裏,這是一種老辦法)。由於微軟沒有提供內置的散列組合方法,因此許多自制的散列函數會產生較差的分佈,所以有時候素數選擇會得到補償,直到散列函數產生多個素數。 – 2013-03-21 00:40:21

8

檢查源,對於List<T>Dictionary<TKey, TValue>默認容量爲0

+4

在.Net 4.5中,附加容量實際上是3.是的,默認構造函數調用容量值爲0的重載構造函數,但構造函數調用Initialize方法時,大小設置爲3。字典是通過調用HashHelpers.GetPrime(容量)來確定的,該容量返回大於所提供容量的下一個素數。因此,在.Net 4.5中,字典的初始容量爲3. 列表的默認容量爲0,但在將第一項添加到列表後,容量將變爲4。 – 2014-08-22 15:57:42

6

如果你知道的大小,然後告訴它;在大多數「小」情況下進行較小的優化,但對於較大的收集有用。我會主要是擔心如果我扔了一個「體面」的數據量,因爲它可以避免不得不分配,複製和收集多個數組。

大多數藏品確實使用雙倍增加的策略。

1

ConcurrentDictionary(當前)並使用其構造函數設置初始大小的另一個問題是其性能似乎受到阻礙。

例如,here's some example code and benchmarks我試過了。

我在機器上運行了代碼,得到了類似的結果。

也就是說,當指定初始大小時,它在增加對象時不會增加ConcurrentDictionary的速度。從技術上講,我認爲應該,因爲它不必花費時間或資源來調整自己的大小。

是的,它的運行速度可能不如普通Dictionary,但我仍然希望ConcurrentDictionary的初始大小設置爲與沒有初始大小設置的ConcurrentDictionary相比具有一致的,更快的性能,特別是當人們事先知道要添加到其中的項目的數量。

因此,故事的寓意是設置初始大小並不總能保證性能的提高。