一. Dictionary與Hashtable
Dictionary與Hashtable都是.Net Framework中的字典類,能夠根據鍵快速查找值
二者的特性大體上是相同的,有時可以把Dictionary<K,V>看做是Hashtable的泛型版本。不過Hashtable是線程安全的,Dictionary是有序的。
字典的性能取決於鍵類型的GetHashCode()方法的實現代碼。
鍵類型也必須實現IEquatable<T>.Equals()方法,並且如果A.Equals(B)返回true,則A和B的GetHashCode()也必須返回相同的值。
Dictionary
- 有泛型優勢(類型安全,性能更好),對於值類型,不存在裝箱和拆箱的性能損耗
- 讀取速度快(體現在單條數據上)
- 容量利用更充分
- 有序(遍歷時輸出的順序就是加入的順序)
Hashtable
- 適合多線程
- 通過靜態方法Synchronize方法可獲得完全線程安全的類型
- 無序
二.List與Dictionary
List有點類似於Dictionary。二者都具有使用泛型的優點,Dictionary沒有在內存中移動后續元素的性能開銷。
List是在數組的基礎上做的封裝,遍歷查詢更快(數據較多時),Dictionary單條查詢更快
引用某一篇文章的分析:
同樣是集合,為什么性能會有這樣的差距。我們要從存儲結構和操作系統的原理談起。
首先我們清楚List<T>是對數組做了一層包裝,我們在數據結構上稱之為線性表,而線性表的概念是,在內存中的連續區域,除了首節點和尾節點外,每個節點都有着其唯一的前驅結點和后續節點。我們在這里關注的是連續這個概念。
而HashTable或者Dictionary,他是根據Key和Hash算法分析產生的內存地址,因此在宏觀上是不連續的,雖然微軟對其算法也進行了很大的優化。
由於這樣的不連續,在遍歷時,Dictionary必然會產生大量的內存換頁操作,而List只需要進行最少的內存換頁即可,這就是List和Dictionary在遍歷時效率差異的根本原因。6. 再談Dictionary
也許很多人說,既然Dictionary如此強大,那么我們為什么不用Dictionary來代替一切集合呢?
在這里我們除了剛才的遍歷問題,還要提到Dictionary的存儲空間問題,在Dictionary中,除了要存儲我們實際需要的Value外,還需要一個輔助變量Key,這就造成了內存空間的雙重浪費。
而且在尾部插入時,List只需要在其原有的地址基礎上向后延續存儲即可,而Dictionary卻需要經過復雜的Hash計算,這也是性能損耗的地方。
簡單的做了下測試
測試代碼

using System.Collections; using System.Collections.Generic; namespace ConsoleApp { class Program { public const int TOTAL_COUNT = 1000000; public static void Main(string[] args) { ListTest(); DicTest(); HashtableTest(); ListInsertTest(); } private static void HashtableTest() { Hashtable ht = new Hashtable(); for (int i = 0; i < TOTAL_COUNT; i++) { ht.Add(i, new Model { Num = i }); } } public static void ListTest() { List<Model> list = new List<Model>(); for (int i = 0; i < TOTAL_COUNT; i++) { list.Add(new Model { Num = i }); } } public static void ListInsertTest() { List<Model> list = new List<Model>(); list.Insert(0, new Model { Num = 0 }); list.Insert(1, new Model { Num = 1 }); for (int i = 2; i < TOTAL_COUNT; i++) { list.Insert(1,new Model { Num = i }); } } public static void DicTest() { Dictionary<int, Model> dic = new Dictionary<int, Model>(); for (int i = 0; i < TOTAL_COUNT; i++) { dic.Add(i, new Model { Num = i }); } } public class Model { public int Num { set; get; } } } }
這個測試總共有四個插入數據方式:Hashtable.Add,Dictionary.Add,List.Add,List.Insert
字典中插入的Key都是int類型。 結果如下

方法中插入次數都是100W 因為實在等不下去了,就中途結束了。
不過這基本不影響分析結果,因為拖后腿的是List.Insert,在只執行了28W的情況下就已經占到了總耗時的95%。
從結果中可以看到插入效率依次是
List.Add -> Dictionary.Add -> Hashtable.Add -> List.Insert
這個結果也符合上面的分析。
下面在實測一下遍歷
遍歷測試代碼

using System.Collections; using System.Collections.Generic; using System.Linq; namespace ConsoleApp { class Program { public const int TOTAL_COUNT = 1000000; public static void Main(string[] args) { List<Model> list = new List<Model>(); for (int i = 0; i < TOTAL_COUNT; i++) { list.Add(new Model { Num = i }); } Hashtable ht = new Hashtable(); for (int i = 0; i < TOTAL_COUNT; i++) { ht.Add(i,new Model { Num = i }); } Dictionary<int, Model> dic = list.ToDictionary(l=>l.Num); ListTest(list); DicTest(dic); HashtableTest(ht); } private static void HashtableTest(Hashtable ht) { foreach (var key in ht.Keys) { var rst = ht[key]; } } public static void ListTest(List<Model> list) { foreach (var item in list) { var rst = item; } } public static void DicTest(Dictionary<int, Model> dic) { foreach (var key in dic.Keys) { var rst = dic[key]; } } public class Model { public int Num { set; get; } } } }
還是100W條數據
List -> Dictionary -> Hashtable