潍坊大型做网站建设的公司,一件代发货源开网店货源,网站建设包含哪些建设阶段,免费 wordpress最近在做项目时#xff0c;多线程中使用Dictionary的全局变量时#xff0c;发现数据并没有存入到Dictionary中#xff0c;但是程序也没有报错#xff0c;经过自己的一番排查#xff0c;发现Dictionary为非线程安全类型#xff0c;因此我感觉数据没有写进去的原因是多线程…最近在做项目时多线程中使用Dictionary的全局变量时发现数据并没有存入到Dictionary中但是程序也没有报错经过自己的一番排查发现Dictionary为非线程安全类型因此我感觉数据没有写进去的原因是多线程在争夺全局变量时导致数据未写入于是去对Dictionary进行仔细的了解。 经过在网上查阅资料发现大家讲解最多的是Dictionary(非线程安全)和ConcurrentDictionary(线程安全)于是我也从这两个关键字来仔细的讲解顺便也更加深入的认识它们。 Dictionary怎样解决线程安全问题可以使用加锁、线程全局变量、使用ConcurrentDictionary等。下面我们就一起来看看吧Let’s go。
Dictionary
DictionaryTKey, TValue泛型类提供了键值对映射通过TKey来检索值的速度非常快时间复杂度接近与O(1)是因为Dictionary通过哈希表实现是一种变相的HashTable采用分离链接散列表的数据结构解决哈希冲突问题。 在早期的C#版本中可以将集合初始值设定项用于序列样式集合包括在键值对周围添加括号而得到DictionaryTKey, TValue如
Dictionaryint, string msgs new Dictionaryint, string()
{{ 1, Hello, },{ 2 , World},{ 3, !}
};而新的语法支持使用索引分配到集合中如
Dictionaryint, string MsgErrs new Dictionaryint, string()
{[1] Hello, ,[2] World,[3] !,
};上述两者在初始化赋值时都差不多但是两者还是有一些区别前者在初始化时出现重复key值程序会直接报错。而后者初始化时key可以有重复值系统会自动过滤掉重复的key值程序也不会报错。 实现键/值对集合 每次对字典的添加都包含一个值与其关联的值通过使用键来检索十分方便 如果使用集合初始值设定项生成Dictionary集合可以使用如下方法
public static Dictionarystring, Element BuildDic(){return new Dictionarystring, Element{{L, new Element(){Symbol L, Name Postass, AutominNumber 9}},{Q, new Element(){ Symbol Q, Name Calcium, AutominNumber 99}},{M, new Element(){ Symbol JY, Name JYaoiang, AutominNumber7924}}};}Dictionary添加值
public static void IterateDictionary(){Dictionarystring, Element element BuildDic();foreach(KeyValuePairstring, Element keyValue in element){Element ele keyValue.Value;Console.WriteLine(string.Format(Key{0}; Values{0};{1};{2}, keyValue.Key, ele.Symbol, ele.Name, ele.AutominNumber));}}public static Dictionarystring, Element BuildDictionary(){var elements new Dictionarystring, Element();AddDictionary(elements, L, LLL, 9);AddDictionary(elements, J, LJLHHH, 19);AddDictionary(elements, A, ABABABA, 20);return elements;}public static void AddDictionary(Dictionarystring, Element elements, string symbol, string name, int num){Element ele new Element(){Symbol symbol,Name name,AutominNumber num};elements.Add(key: symbol, value: ele);}ContainsKey方法和Item[]属性
public static void FindDictionary(string symbol){Dictionarystring, Element elements BuildDictionary();if (elements.ContainsKey(symbol)){Element ele elements[symbol];Console.WriteLine(Found: ele.Name);}else{Console.WriteLine(Not found symbol);}}TryGetValue方法
public static void FindDictionaryOfTryGetValue(string symbol){Dictionarystring, Element elements BuildDictionary();Element ele null;if(elements.TryGetValue(symbol, out ele)){Console.WriteLine(Found: ele.Name);}else{Console.WriteLine(Not found symbol);}}在这里讲解了Dictionary的常见使用方法这里在啰嗦一句不知道大家在使用Dictionary时有没有注意带Add方法和TryAdd方法这两个方法到底有什么区别 我们都知道在往Dictionary中添加键值时键是不能重复的如果使用Add方法添加重复的key会使程序报错。要想避免这个问题则可以使用TryAdd方法当添加重复键值使该方法会返回false就可以避免此类问题。
ConcurrentDictionary
在.NET Framework 4以及更新的版本中System.Collections.Concurrent命名空间中的集合可提供高效的线程安全操作以便从多个线程访问集合项。 当有多个线程访问集合项时应该使用System.Collections.Concurrent命名空间中的类而不是使用System.Collections.Generic和System.Collections命名空间中的类。 System.Collections.Concurrent命名空间中的类BlockingCollection、ConcurrentDictionaryTKey, TValue、ConcurrentQueueT、ConcurrentStackT。 System.Collections命名空间中的类不会将元素作为特别类型化的对象存储而是作为object类型的对象存储。 ConcurrentDictionary用法与Dictionary类似这里就不再详细讲解了。但是ConcurrentDictionary只能使用TryAdd方法而Dictionary可以使用Add和TryAdd方法。
Dictionary和ConcurrentDictionary多线程
带大家认识完Dictionary和ConcurrentDictionary下面就回归主题看看两者在多线程方面的使用情况。 代码如下
ConcurrentDictionaryint, string keys new ConcurrentDictionaryint, string();
keys.TryAdd(1, LL);
keys.TryAdd(2, LL);
Dictionaryint, string dic new Dictionaryint, string();
dic.Add(1, OJ);
dic.TryAdd(2, R);
Stopwatch stopwatch new Stopwatch();
#region 写入
stopwatch.Start();
Parallel.For(0, 10000000, i
{lock (dic){dic[i] new Random().Next(100, 99999).ToString();}
});
stopwatch.Stop();
Console.WriteLine(Dictionary加锁写入花费时间{0}, stopwatch.Elapsed);
stopwatch.Restart();
Parallel.For(0, 10000000, i
{keys[i] new Random().Next(100, 99999).ToString();
});
stopwatch.Stop();
Console.WriteLine(ConcurrentDictionary加锁写入花费时间{0}, stopwatch.Elapsed);
#endregion
#region 读取
string result string.Empty;
stopwatch.Restart();
Parallel.For(0, 10000000, i
{lock (dic){result dic[i];}
});
stopwatch.Stop();
Console.WriteLine(Dictionary加锁读取花费时间{0}, stopwatch.Elapsed);
stopwatch.Restart();
Parallel.For(0, 10000000, i
{result keys[i];
});
stopwatch.Stop();
Console.WriteLine(ConcurrentDictionary加锁读取花费时间{0}, stopwatch.Elapsed);
#endregion
Console.ReadLine();可以发现在多线程下加了lock的Dictionary写入性能要比ConconcurrentDictionary的写入性能更好读取数据ConcurrentDictionary性能更好。 当我们将写入的数据增加到20000000时ConcurrentDictionary写入性能明显就比Dictionary性能差了但是读取性能ConcurrentDictionary更好。 当我们将写入的数据增加到2000000时ConcurrentDictionary写入性能还是比Dictionary性能差但是读取性能ConcurrentDictionary更好。 综上经过对两者的比较ConcurrentDictionary读取性能更好Dictionary写入性能更好。 至于具体是什么原因到时候我会进行深入讲解这篇文章大致就讲到这里了我们下篇文章见。