HashTable,Dictionary,ConcurrentDictionary 的应用场景,区别,用法统计

摘要:
在.NETFramework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似key-value的键值对,其中key通常可用来快速查找,同时key是区分大小写;value用于存储对应于key的值。原因在于Hashtable与Dic采用的是不同的数据结构。eaglet的“Dictionary由于在Hashtable基础上封装了一层”这个说法是不对的。Dictionary调用Add方法之前使用ContainsKey方法测试某个键是否存在,否则得到一个KeyNotFoundException。url:http://www.cnblogs.com/jhh0111/archive/2008/10/23/1318223.html我认为应该始终使用Dictionary,即使要用Hashtable了,也可以用Dictionary来替代。关于Hashtable与Dictionary性能的讨论。

https://www.cnblogs.com/yinrq/p/5584885.html

一、HashTable

HashTable表示键/值对的集合。在.NET Framework中,Hashtable是System.Collections命名空间提供的一个容器,用于处理和表现类似key-value的键值对,其中key通常可用来快速查找,同时key是区分大小写;value用于存储对应于key的值。Hashtable中key-value键值对均为object类型,所以Hashtable可以支持任何类型的keyvalue键值对,任何非 null 对象都可以用作键或值。

HashTable是一种散列表,他内部维护很多对Key-Value键值对,其还有一个类似索引的值叫做散列值(HashCode),它是根据GetHashCode方法对Key通过一定算法获取得到的,所有的查找操作定位操作都是基于散列值来实现找到对应的Key和Value值的。

散列函数(GetHashCode)让散列值对应HashTable的空间地址尽量不重复。

当一个HashTable被占用一大半的时候我们通过计算散列值取得的地址值可能会重复指向同一地址,这就造成哈希冲突。

C#中键值对在HashTable中的位置Position= (HashCode& 0x7FFFFFFF) % HashTable.Length,C#是通过探测法解决哈希冲突的,当通过散列值取得的位置Postion以及被占用的时候,就会增加一个位移x值判断下一个位置Postion+x是否被占用,如果仍然被占用就继续往下位移x判断Position+2*x位置是否被占用,如果没有被占用则将值放入其中。当HashTable中的可用空间越来越小时,则获取得到可用空间的难度越来越大,消耗的时间就越多。

HashTable使用场景:

. 什么情况下使用哈希表

(1)某些数据会被高频率查询
(2)数据量大
(3)查询字段包含字符串类型
(4)数据类型不唯一

由于 Hashtable 和 Dictionary 同时存在, 在使用场景上必然存在选择性, 并不任何时刻都能相互替代.

[1] 单线程程序中推荐使用 Dictionary, 有泛型优势, 且读取速度较快, 容量利用更充分.
[2] 多线程程序中推荐使用 Hashtable, 默认的 Hashtable 允许单线程写入, 多线程读取, 对 Hashtable 进一步调用 Synchronized() 方法可以获得完全线程安全的类型. 而 Dictionary 非线程安全, 必须人为使用 lock 语句进行保护, 效率大减.
[3] Dictionary 有按插入顺序排列数据的特性 (注: 但当调用 Remove() 删除过节点后顺序被打乱), 因此在需要体现顺序的情境中使用 Dictionary 能获得一定方便.

个人偏向于使用Dictionary,因为其使用泛型,可控性比较强。在一些资料中,很多人也推荐使用Dictionary,其原因主要有

1、Dic是类型安全的,这有助于我们写出更健壮更具可读性的代码,而且省却我们强制转化的麻烦。
2、Dic是泛行的,当K或V是值类型时,其速度远远超过Hashtable。处理对象时不需要进行显式或是隐式转型,进行值类型处理时不需要装箱。所以使用方便一些,而且效率会高一些(编码效率、运行效率),还不太容易出错。

摘自于:https://www.2cto.com/kf/201304/201715.html

3、如果K和V都是引用类型,如eaglet所测,Hashtable比Dic更快,这里我要指出,eaglet所做的测试是有问题的。原因在于Hashtable与Dic采用的是不同的数据结构。eaglet的“Dictionary 由于在Hashtable基础上封装了一层”这个说法是不对的。

Dictionary 调用 Add 方法之前使用 ContainsKey 方法测试某个键是否存在,否则得到一个KeyNotFoundException。
当程序频繁尝试字典中不存在的键时,使用 TryGetValue 方法来检索值,这种方法是一种更有效的检索值的方法。

http://www.cnblogs.com/lucifer1982/archive/2008/06/18/1224319.html
http://www.cnblogs.com/lucifer1982/archive/2008/07/03/1234431.html

Hashtable在指定capacity参数时,它并不只开出capacity个槽的内存空间,而是开出比 capacity / 0.72(默认装填因子) 大的最小素数个槽的空间;而Dic在指定capacity时,是开出 比capacity 大的最小素数个槽的空间。因此可以看到,楼主虽然都指定capacity为10万,而实际上Hashtable的槽的总数远远大于Dic的槽的总数,也就是占用的内存远远大于Dic,因此,如此测试是不公平不公正的,如要公平公正的测试,则应该把Dic的capacity指定为 10万/0.72,请大家再测试其性能。

url:http://www.cnblogs.com/jhh0111/archive/2008/10/23/1318223.html

我认为应该始终使用Dictionary<K, V>,即使要用Hashtable了,也可以用Dictionary<object, object>来替代。

关于Hashtable与Dictionary性能的讨论。:http://www.cnblogs.com/jhh0111/archive/2008/10/23/1318223.html

Dictionary 字典使用经验:

1.通过遍历获取Dictionary 的键值对时,耗时: keys集合遍历 >keyvaluePair遍历

2.单独遍历获取Keys时,keyValPair 遍历 > values 集合遍历 用KeyValuePair反而是累赘

1. 遍历性能,如果想通过遍历获取Dictionary 的键值对,方法有两种

方法 一

/// <summary>
/// 通过key 访问键值对
/// </summary>
private static void keyPerformance(Dictionary<string,string> dic)
{
DateTime start = DateTime.Now;
string val = string.Empty;
string key = string.Empty;
foreach (string item in dic.Keys)
{
key = item;
val = dic[item];
}
DateTime end = DateTime.Now;
TimeSpan span = end.Subtract(start);
Console.WriteLine(" foreach keys spend time:{0}",span.TotalMilliseconds);
}

方法 二 性能最佳 推荐使用

/// <summary>
/// 通过 KeyValuePair 访问键值对(推荐使用)
/// </summary>
/// <param name="dic"></param>
private static void keyValPerformance(Dictionary<string , string> dic)
{
DateTime start = DateTime.Now;
string val = string.Empty;
string key = string.Empty;
foreach (KeyValuePair<string ,string> item in dic)
{
key = item.Key;
val = item.Value;
}
DateTime end = DateTime.Now;
TimeSpan span = end.Subtract(start);

Console.WriteLine(" foreach keyVals spend time:{0}", span.TotalMilliseconds);
}

以下是耗时对比

耗时: keys集合遍历 >keyvaluePair遍历

2. 其它遍历

如果获取 dictionary 中的key 推荐 方法一

耗时: keyvalPair 遍历 >keys 集合遍历

如果获取 dictionary 中的value 推荐如下方法

private static void valPerformance(Dictionary<string , string> dic)
{
DateTime start = DateTime.Now;
string val = "";
foreach (string item in dic.Keys)
{
val = item;
}
DateTime end = DateTime.Now;
TimeSpan span = end.Subtract(start);
Console.WriteLine(" foreach vals spend time:{0}", span.TotalMilliseconds);
}
耗时: keyValPair 遍历 > values 集合遍历

数据结构~时间复杂度:http://www.cnblogs.com/lori/p/3962707.html

扩展阅读:

 C#集合类型大揭秘:https://juejin.im/post/5b22ff4d51882574874d86c5

免责声明:文章转载自《HashTable,Dictionary,ConcurrentDictionary 的应用场景,区别,用法统计》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Golang源码探索(二) 协程的实现原理(转)excel间隔取值的三种公式写法-转载下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

JAVA 调用HTTP接口POST或GET实现方式(转)

HTTP是一个客户端和服务器端请求和应答的标准(TCP),客户端是终端用户,服务器端是网站。通过使用Web浏览器、网络爬虫或者其它的工具,客户端发起一个到服务器上指定端口(默认端口为80)的HTTP请求。 具体POST或GET实现代码如下: packagecom.yoodb.util; importjava.io.ByteArrayOutputStre...

C#读取EXCEL文件的三种经典方法

1.方法一:采用OleDB读取EXCEL文件: 把EXCEL文件当做一个数据源来进行数据的读取操作,实例如下: public DataSet ExcelToDS(string Path)  {  string strConn = "Provider=Microsoft.Jet.OLEDB.4.0;" +"Data Source="+ Path +";...

C#.图片拖动处理(摘抄)

本文摘自博客园牛人吉日嘎啦。 通用权限管理系统组件源码里,有职员管理的功能,实现了直接可以把照片拖拽过来的功能,用起来会很方便。 想要控件支持拖拽,需要设置 AllowDrop 属性。 还需要写下面的2个事件。 参考代码如下,有需要的可以参考一下,把有需要的代码参考一下就可以了。 //---------------------------------...

java8 的files、path类相关文件遍历API

Path的两种初始化(应该还有别的方式) Path file = new File(path).toPath(); Paths.get 判断是文件、是目录 Files.isRegularFile(file) Files.isDirectory(file) javadoc说,还有既不是文件也不是目录的情况 Files.find 通过属性和路径筛选,可以筛选是...

Hadoop 序列化

摘自:http://blog.csdn.net/zhang0558/article/details/53444533 序列化和反序列化以及hadoop数据类型 1.什么是序列化和反序列化   序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储(持久化)和网络传输。   反序列化就是将收到 字节序列(或其他数据传输协议)或者是硬盘的持久...

算法导论10.顺序统计树与区间树习题

顺序统计树和区间树都是对红黑树的扩张:通过在节点添加字段完成其他的功能,如果该字段可以在 $O(1)$ 时间内维护,就能够不影响红黑树本身操作效率渐进量级。 顺序统计树 顺序统计树是红黑树的扩展:在红黑树的每个节点额外维护一个域size,记录以该节点为根的子树中的总结点个数。顺序统计数具有这样的功能:在 $O(\lg n)$ 时间内找到树中所有元素的第 $...