Ash*_*kru 38 c# dictionary concurrentdictionary
我总是对选择哪一个感到困惑.当我看到它,我用Dictionary
了List
,如果我想两个数据类型为Key
和Value
这样我就可以很容易地找到它的价值key
,但我总是困惑,如果我要使用一个ConcurrentDictionary
或Dictionary
?
在我离开之前没有对此进行太多研究之前我已经尝试过,但似乎谷歌并没有真正得到任何关于Dictionary
vs ConcurrentDictionary
但是每个人都有一些东西.
我之前曾问过这样的朋友,但他们所说的只是:" ConcurrentDictionary
如果你在代码中使用了很多字典就会使用",我真的不想纠缠他们来更详细地解释它.任何人都可以扩展这个吗?
Jef*_*f B 47
"如果你在代码中大量使用你的字典,请使用ConcurrentDictionary"是一种模糊的建议.我不会因为混乱而责备你.
ConcurrentDictionary
主要用于从多个线程(或异步任务)更新字典的环境中.Dictionary
如果它来自单个线程,您可以使用尽可能多的代码标准;)
如果你看一下在ConcurrentDictionary的方法,你会发现一些有趣的方法,如TryAdd
,TryGetValue
,TryUpdate
,和TryRemove
.
例如,考虑一个典型的模式,您可能会看到使用普通Dictionary
类.
// There are better ways to do this... but we need an example ;)
if (!dictionary.ContainsKey(id))
dictionary.Add(id, value);
Run Code Online (Sandbox Code Playgroud)
这有一个问题,在检查它是否包含密钥和调用Add
不同的线程之间可以调用Add
它id
.当这个线程调用时Add
,它会抛出异常.该方法TryAdd
为您处理,并将返回一个true/false,告诉您是否添加了它(或者该键是否已经在字典中).
因此,除非您在多线程代码段中工作,否则您可能只需使用标准Dictionary
类.话虽这么说,理论上你可以有锁来防止并发访问字典; 该问题已在"字典锁定与ConcurrentDictionary"中解决.
ConcurrentDictionary
过度使用的最大原因Dictionary
是线程安全。如果您的应用程序将同时使用同一个字典获得多个线程,则您需要线程安全ConcurrentDictionary
,当这些线程写入或构建字典时尤其如此。
ConcurrentDictionary
不使用多线程的缺点是开销。所有允许它是线程安全的函数仍然存在,所有的锁和检查仍然会发生,需要处理时间并使用额外的内存。
ConcurrentDictionary
当您想要一个可以由多个线程同时安全访问的高性能字典时,A非常有用。Dictionary
与使用 a 保护的标准相比lock
,由于其细粒度锁定实现,它在大量使用时效率更高。不是所有线程都竞争单个锁,而是ConcurrentDictionary
在内部维护多个锁,从而最大限度地减少争用,并限制成为瓶颈的可能性。
尽管有这些很好的特性,但使用 a 是最佳选择的场景ConcurrentDictionary
实际上很少。原因有二:
提供的线程安全保证ConcurrentDictionary
仅限于保护其内部状态。就是这样。如果您想做一些稍微不平凡的事情,例如将字典和另一个变量更新为原子操作,那么您就不走运了。这不是ConcurrentDictionary
. 甚至不支持保护它包含的元素(如果它们是可变对象)。如果您尝试使用该方法更新其值之一AddOrUpdate
,则字典将受到保护,但该值不会受到保护。Update
在此上下文中的意思是用另一个值替换现有值,而不是修改现有值。
每当您发现想使用 a 时ConcurrentDictionary
,通常都有更好的替代方案可用。不涉及共享状态的替代方案,而共享状态本质上就是共享状态ConcurrentDictionary
。无论其锁定方案多么有效,它都很难击败根本没有共享状态的体系结构,并且每个线程都做自己的事情而不干扰其他线程。遵循此原则的常用库是PLINQ和TPL Dataflow库。下面是一个 PLINQ 示例:
Dictionary<string, Product> dictionary = productIDs
.AsParallel()
.Select(id => GetProduct(id))
.ToDictionary(product => product.Barcode);
Run Code Online (Sandbox Code Playgroud)
您可以相信 PLINQ 会利用更高效的策略生成字典,包括对初始工作负载进行分区,并将每个分区分配给不同的工作线程,而不是预先创建字典,然后让多个线程同时向其中填充值。单个线程最终将聚合部分结果并填充字典。
ConcurrentDictionary
当您需要跨多个线程(即多线程)访问字典时非常有用。VanillaDictionary
对象不具备此功能,因此只能以单线程方式使用。