.NET HashTable与字典-字典可以这么快吗?


276

我试图弄清楚何时以及为什么使用Dictionary或HashTable。我在这里做了一些搜索,发现人们谈论我完全同意的《词典》的一般优势,这导致装箱和拆箱的优势略有提高。

但是我也读过Dictionary并不会总是按插入对象的顺序返回对象,而是对其进行排序。像HashTable一样。据我了解,这导致HashTable在某些情况下会快得多。

我的问题是,这些情况可能是什么?我在上面的假设中错了吗?您可能会使用哪种情况来选择另一种情况(是的,最后一种情况有点模棱两可)。


5
我不想对此表示赞成,但您的因果报应是7,777,我不想成为为您搞砸的人。
CaptainMarvel '18年

Answers:


298

System.Collections.Generic.Dictionary<TKey, TValue>System.Collections.Hashtable类都在内部维护哈希表数据结构。它们都不能保证保留项目的顺序。

除了装箱/拆箱问题外,大多数情况下,它们应该具有非常相似的性能。

它们之间的主要结构差异是Dictionary依靠链接(为每个哈希表存储桶维护一个项目列表)来解决冲突,而Hashtable使用重新哈希化来解决冲突(当发生冲突时,尝试使用另一个哈希函数将键映射到存储桶) 。

Hashtable如果您面向.NET Framework 2.0+ ,则使用类几乎没有好处。有效地使它过时了Dictionary<TKey, TValue>


21
@ Jon-的链接和重散列在深度这里-讨论msdn.microsoft.com/en-us/library/ms379571(VS.80).aspx
RichardOD

谢谢你们俩。只是在Richard发布时发现了该页面...想要询问Chaining,但是MSDN站点实际上是有帮助的!
乔恩

6
@Mehrdad-对于冲突的解决方式,我不清楚:如果多个键可能导致相同的哈希,那么如何确保在查询中获得正确的值,即函数如何知道要使用哪个元素返回?在 msdn.microsoft.com/zh-CN/library/ms379571%28VS.80%29.aspx中,它说:“与在Hashtable类中进行的碰撞一样,Dictionary不会像发生Hashtable类那样进行重新探测进入存储桶列表。” 这是否意味着在使用Dictionary时,开发人员不必担心冲突?
Howiecamp

6
@Howiecamp:这与并没有太大的不同Hashtable。哈希表在一项中存储3条信息:密钥哈希,密钥本身和值。对于具有相等哈希值的项目,必须遍历列表以找到具有相同键的项目并返回其值。这几乎Hashtable也是正确的。作为Dictionary通常使用的开发人员,您无需担心。
Mehrdad Afshari'2

@Mehrdad需要明确的是,Hashtable和Dictionary对象都存储密钥本身,并且都隐藏了开发人员的冲突吗?
Howiecamp

111

我想现在对您没有任何意义。但仅供参考

性能测试-SortedList,SortedDictionary,字典,哈希表

内存分配:

内存使用性能测试

插入时间:

插入时间

搜索项目的时间:

搜索项目的时间


非常有趣的是,排序列表比散列表具有更快的查找速度。我认为哈希表是O(1)与排序列表O(logn)。显然哈希表很烂。我永远不会使用它。
John Henckel

@JohnHenckel不,排序列表的查找速度较慢。更高的性能系数意味着更好的性能和更好的内存使用率。因此,根据图表,排序后的列表具有最佳的内存使用率,但在其他方面(例如插入和查找)却很糟糕。
C0DEF52

31

哈希表和字典之间的区别

字典:

  • 如果我们尝试找到不存在的键,则字典返回错误。
  • 字典比哈希表更快,因为没有装箱和拆箱。
  • 字典是一种通用类型,这意味着我们可以将其与任何数据类型一起使用。

哈希表:

  • 如果我们尝试查找不存在的键,则Hashtable返回null。
  • 哈希表比字典慢,因为它需要装箱和拆箱。
  • 哈希表不是通用类型,

24

另一个重要的区别是Hashtable类型同时支持无锁的多个读取器和一个写入器,而Dictionary不支持。


8
并发字典将支持(.Net 4.0)
Tamilmaran 2012年

1
我不确定我是否理解此答案。在此处查看msdn.microsoft.com/zh-cn/library/…它说:“要支持多个编写器,必须对Hashtable进行所有操作,必须通过Synchronized方法返回的包装器来完成,前提是没有线程读取Hashtable对象。 ” 这似乎使“无锁多个读取器”功能变得毫无用处,因此我们又回到了必须锁定对哈希表的所有访问权限的方式,就像使用Dictionary一样。
RenniePet 2015年


11

两者实际上是同一类(您可以查看反汇编)。HashTable是在.Net具有泛型之前首先创建的。但是,Dictionary是一个泛型类,可为您提供强大的键入优势。我永远不会使用HashTable,因为Dictionary不需要您花钱。


8

另一个重要的区别Hashtable是线程安全。Hashtable内置了多个读取器/单个写入器(MR / SW)线程安全性,这意味着Hashtable允许一个写入器与多个读取器一起使用而不会锁定。在Dictionary没有线程安全的情况下,如果需要线程安全,则必须实现自己的同步。

详细说明:

Hashtable,通过Synchronized属性提供一些线程安全性,该属性返回围绕集合的线程安全包装器。包装器通过在每个添加或删除操作上锁定整个集合来工作。因此,每个试图访问该集合的线程都必须等待其轮换获得一个锁。这是不可扩展的,并且可能导致大型集合的显着性能下降。此外,该设计也没有完全不受竞争条件的影响。

.NET Framework 2.0中的集合类一样 List<T>Dictionary<TKey, TValue>等不提供任何线程同步; 同时在多个线程上添加或删除项目时,用户代码必须提供所有同步。如果既需要类型安全又需要线程安全,请在.NET Framework中使用并发集合类。在这里进一步阅读。


3

字典具有作为通用类型的优点,由于不需要装箱,因此使其类型安全且速度更快。以下比较表(使用类似的SO 问题帖子中的答案构建)说明了支持哈希表字典的其他一些原因(反之亦然)。


1

如果您关心的是读取将始终按插入字典中的对象的顺序返回的对象,则可以查看一下

OrderedDictionary-可以通过整数索引访问值(按添加项目的顺序) SortedDictionary-项目自动排序


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.