29

正如MSDN 所说

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

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

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

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

在第 5 部分中,Joseph Albahari 提到它是为并行编程而设计的

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

5 回答 5

19

如果不知道更多关于你在锁内做什么,那么就不可能说。

例如,如果您的所有字典访问都如下所示:

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

... // elsewhere

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

然后你就可以把它换掉(尽管你可能不会看到性能上有任何差异,所以如果它没有坏,就不要修复它)。但是,如果您在与字典交互的锁定块中做任何花哨的事情,那么您必须确保字典提供一个可以完成您在锁定块中所做的事情的函数,否则您' 最终会得到功能上与以前不同的代码。要记住的最重要的事情是字典只保证对字典的并发调用以串行方式执行;它无法处理代码中的单个操作字典多次交互的情况。诸如此类的情况,ConcurrentDictionary,需要你自己的并发控制。

值得庆幸的是,ConcurrentDictionary它为更常见的多步操作提供了一些辅助函数,例如AddOrUpdateor GetOrAdd,但它们不能涵盖所有情况。如果您发现自己不得不努力将您的逻辑硬塞到这些函数中,那么处理您自己的并发可能会更好。

于 2011-03-14T19:37:14.047 回答
5

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

例如,不是调用Addor Remove,而是使用TryAddand TryRemove。使用这些原子行为的方法很重要,就好像您进行两次调用,其中第二次调用取决于第一次的结果,您仍然会有竞争条件并且需要一个lock.

于 2011-03-14T19:40:19.867 回答
1

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

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

于 2011-03-14T19:35:46.547 回答
1

虽然我不确定更换困难,但如果您有任何地方需要在同一个“锁定会话”中访问字典中的多个元素,那么您需要修改您的代码。

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

于 2011-03-14T19:36:18.640 回答
0

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

于 2011-03-14T19:37:48.603 回答