ConcurrentDictionary <tkey,tvalue> vs Dictionary <tkey,tvalue> </tkey,tvalue> </tkey,tvalue>

时间:2011-03-14 19:32:23

标签: c# c#-4.0 dictionary concurrent-collections

作为MSDN says

ConcurrentDictionary<TKey, TValue> Class表示可由多个线程同时访问的键值对的线程安全集合。

但据我所知,System.Collections.Concurrent类是为PLINQ设计的。

我有Dictionary<Key,Value>在服务器中保留在线客户端,并且当我有权访问它时,我通过锁定对象使其成为线程安全。

在我的情况下,我可以安全地将Dictionary<TKey,TValue>替换为ConcurrentDictionary<TKey,TValue>吗?更换后性能会提高吗?

第5部分中的

Here Joseph Albahari提到它是为并行编程而设计的

  • 并发集合针对并行编程进行了调整。除了高度并发的场景之外,传统的集合在所有集合中都优于它们。
  • 线程安全集合不保证使用它的代码是线程安全的。
  • 如果在另一个线程正在修改它时枚举并发集合,则不会抛出任何异常。相反,你会得到新旧内容的混合。
  • 没有List的并发版本。
  • 并发堆栈,队列和包类在内部使用链接列表实现。这使得它们比非并发Stack和Queue类的内存效率更低,但对并发访问更好,因为链表有利于无锁或低锁实现。 (这是因为将节点插入链表需要更新几个引用,而将元素插入类似List的结构可能需要移动数千个现有元素。)

5 个答案:

答案 0 :(得分:16)

如果不知道你在锁中做了什么,那就不可能说了。

例如,如果您的所有词典访问都是这样的:

lock(lockObject)
{
    foo = dict[key];
}

... // elsewhere

lock(lockObject)
{
    dict[key] = foo;
}

然后你可以将它切换出来(虽然你可能不会看到性能上的任何差异,所以如果没有破坏,不要修复它)。但是,如果您在与字典交互的锁定块中执行任何操作,那么您必须确保字典提供单个函数,该函数可以完成您正在执行的操作在锁定块内,否则您将得到与以前功能不同的代码。要记住的最重要的事情是字典只保证对字典的并发调用以串行方式执行;它无法处理您在 代码中单个操作的情况,该代码多次与字典交互。这种情况,如果没有ConcurrentDictionary解释,则需要你自己的并发控制。

值得庆幸的是,ConcurrentDictionary为更常见的多步操作提供了一些辅助函数,例如AddOrUpdateGetOrAdd,但它们无法涵盖所有​​情况。如果你发现自己不得不把你的逻辑搞砸到这些函数中,那么处理你自己的并发可能会更好。

答案 1 :(得分:3)

这不像用Dictionary替换ConcurrentDictionary那么简单,您需要调整代码,因为这些类具有不同行为的新方法,以保证线程安全。

例如,您没有致电AddRemove,而是TryAddTryRemove。重要的是你使用这些原子行为的方法,就像你进行两次调用,其中第二次依赖于第一次的结果,你仍然会有竞争条件,需要lock

答案 2 :(得分:1)

您可以将Dictionary<TKey, TValue>替换为ConcurrentDictionary<TKey, TValue>

对性能的影响可能不是你想要的(如果有很多锁定/同步,性能可能会受到影响......但至少你的集合是线程安全的。)

答案 3 :(得分:1)

虽然我不确定替换困难,但如果您在同一个“锁定会话”中需要访问字典中的多个元素,则需要修改代码。

如果Microsoft为读写提供了单独的锁,它可以提高性能,因为读操作不应该阻止其他读操作。

答案 4 :(得分:0)

是的,您可以安全地替换,但是为plinq设计的字典可能有一些额外的代码,用于添加您可能不使用的功能。但性能开销将略微很小。

相关问题