.Net4后ConcurrentDictionary替换Dictionary测试
<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">前言</a></li><ul class="second_class_ul"><li><a href="#_lab2_0_0">Dictionary<TKey, TValue></a></li><li><a href="#_lab2_0_1">ConcurrentDictionary<TKey, TValue></a></li></ul><li><a href="#_label1">ConcurrentDictionary实例测试</a></li><ul class="second_class_ul"></ul><li><a href="#_label2">小妙招</a></li><ul class="second_class_ul"></ul></ul></div><p>在.NET Framework 4.0中,增加了ConcurrentDictionary。<code>ConcurrentDictionary<TKey, TValue></code> 继承自 <code>Dictionary<TKey, TValue></code>,因此它支持大部分标准的字典操作,如添加、查找、删除等。但是,它还提供了一些额外的线程安全方法,比如 <code>TryAdd</code>, <code>TryUpdate</code>, <code>TryRemove</code> 等。</p><p class="maodian"><a name="_label0"></a></p><h2>前言</h2>
<p class="maodian"><a name="_lab2_0_0"></a></p><h3>Dictionary<TKey, TValue></h3>
<p>1、泛型类提供了从一组键到一组值的映射。通过键来检索值的速度是非常快的,这是因为 Dictionary<TKey,TValue> 类是作为一个哈希表来实现的。检索速度取决于为 TKey 指定的类型的哈希算法的质量。</p>
<p>2、TValue可以是值类型,数组,类或其他。</p>
<p>3、一个类的实例里,有个属性是个字典,我们不加考虑的会用Dictionary,而当这个属性被提升为static静态的(类级别的)时候,我们就要考虑它的线程安全性了,因为它有可能被多个线程同时访问,当然,如果这个对象是只读的,也无所谓线程安全,但如果这个属性是可以被写的,那就需要把它加锁了。</p>
<p>4、若允许多个线程对集合执行读写操作,您必须实现自己的同步,读写并行的时候需要加锁,但是加上锁性能就会受影响。</p>
<p></p>
<p class="maodian"><a name="_lab2_0_1"></a></p><h3>ConcurrentDictionary<TKey, TValue></h3>
<p>1、表示可由多个线程同时访问的键/值对的线程安全集合。</p>
<p>2、ConcurrentDictionary是.net4.0推出的一套线程安全集合里的其中一个,和它一起被发行的还有ConcurrentStack,ConcurrentQueue等类型,它们的单线程版本(线程不安全的,Queue,Stack,Dictionary)。</p>
<p>3、用法同Dictionary很多相同,但是多了一些方法。ConcurrentDictionary 属于System.Collections.Concurrent 命名空间</p>
<p class="maodian"><a name="_label1"></a></p><h2>ConcurrentDictionary实例测试</h2>
<p>在.NET4.0以前,在多线程环境下如果我们使用Dictionary类,只能自己编码实现线程同步来保证线程安全,别无他选。在.NET4.0以后微软替我们开发了ConcurrentDictionary类,如果你使用字典遇到线程安全的问题,那么就使用ConcurrentDictionary类,不用再考虑“Dictionary+Locks”的问题了。</p>
<p>下面我们对比来看看加锁后的Dictionary和ConcurrentDictionary的使用情况,是否解决了问题下,性能如何呢?</p>
<div class="jb51code"><pre class="brush:csharp;">
string res = "";
var concurrentDictionary = new ConcurrentDictionary<int, string>();
var dictionary = new Dictionary<int, string>();
dictionary.TryAdd(1, "aa");
concurrentDictionary.TryAdd(1,"");
var sw = new Stopwatch();
sw.Start();
Parallel.For(0, 1000000, i =>//Parallel使用并行循环
{
lock (dictionary)
{
dictionary = new Random().Next(1000, 9999).ToString();
}
});
sw.Stop();
Console.WriteLine("加锁写入dictionary {0}", sw.Elapsed);
//wrinting to dictionary with a lock: 00:00:00.0633939
sw.Restart();
Parallel.For(0, 1000000, i =>
{
concurrentDictionary = new Random().Next(1000, 9999).ToString();
});
sw.Stop();
Console.WriteLine("concurrentdictionary写入时长 : {0}", sw.Elapsed);
sw.Restart();
Parallel.For(0, 1000000, i =>
{
lock (dictionary)
{
res = dictionary;
}
});
sw.Stop();
Console.WriteLine("读取dictionary耗时: {0}", sw.Elapsed);
sw.Restart();
Parallel.For(0, 1000000, i =>
{
res = concurrentDictionary;
});
sw.Stop();
Console.WriteLine("读取concurrentdictionary耗时: {0}", sw.Elapsed);
Console.ReadLine();</pre></div>
<p>结果如下</p>
<p><img alt="ConcurrentDictionary" src="https://img.jbzj.com/file_images/article/202505/202552490506941.png" /></p>
<p></p>
<p>ConcurrentDictionary和Dictionary运行结果显示,读取写入的效率都是ConcurrentDictionary胜出,完美,也未出现线程安全的问题。注意环境关系可能略有差距。据说在多核多线程的情况下concurrentDictionary将有更好的性能表现。</p>
<p>面试官也可能问Dictionary怎么解决线程安全问题,如果答出使用ConcurrentDictionary一定是加分项。</p>
<p>注意,有网友指出ConcurrentDictionary使用依然会有线程安全问题,楼主目前没有发现,大家可以自己试一试。</p>
<p class="maodian"><a name="_label2"></a></p><h2>小妙招</h2>
<p>tryadd的使用,在字典中添加的时候,集合里已经包含了指定的key,Add方法会出错,抛出异常,如果使用tryadd就会避免这个问题,添加失败会返回false。</p>
<div class="jb51code"><pre class="brush:csharp;">dictionary.TryAdd(1, "aa");
concurrentDictionary.TryAdd(1,"");</pre></div>
<p>注意ConcurrentDictionary只支持TryAdd,普通Dictionary的TryAdd和Add都支持。</p>
頁:
[1]