【问题标题】:C# ConcurrentDictionary used by 3 threads3 个线程使用的 C# ConcurrentDictionary
【发布时间】:2014-10-17 09:14:06
【问题描述】:

我有一个使用ConcurrentDictionary 的类。

在这个类中,有三个函数对这个ConcurrentDictionnary执行一些操作。

每个函数都由不同的线程调用。

  • 第一个函数操作:dictionnary.Where,dictionnary.TryRemove
  • 第二个函数操作:dictionnary.Where
  • 第三个函数操作:dictionnary.TryAdd

while (!dictionnaryKey.TryAdd(key, item))
{
  LogWriter.error_log("try add to dictionnary ...");
}

最后一个函数在不同的时间阻塞。我必须在不阻塞的情况下将我的元素添加到字典中,但我该怎么做?

【问题讨论】:

  • 为什么要不阻塞地添加元素?这不会破坏阻塞集合的全部目的,并且最重要的是您会失去线程安全性。您不妨使用普通字典。
  • 带锁的普通字典的性能将低于并发字典。您如何衡量阻塞?...您同时运行多少个线程?
  • 这样做的一种选择是有一个额外的线程来负责添加和删除以及 2 堆字典,一个用于添加,另一个用于删除。如果您想在任何线程中添加某些内容,请将其添加到添加堆栈(与删除相同)。在额外的线程中,您检查 1 秒间隔(或其他)是否有任何堆栈中的内容,然后相应地执行该操作,首先从添加堆栈中添加所有内容,然后从删除堆栈中删除所有内容
  • 枚举字典并同时写入它可能会返回在任何时间点都不存在的混合结果。我怀疑你的整个概念并不像你想象的那么安全。

标签: c# multithreading concurrentdictionary blockingcollection


【解决方案1】:
I have to add my element to the dictionary without blocking, but how can I do?

这是不可能的。 ConcurrentDictionary 针对多线程和低争用进行了优化,但这并不意味着没有争用(阻塞)。 ConcurrentDictionary 中的所有写操作都使用fine-grained-locking模型,内部使用多个锁对象同步写操作,以保持数据一致,防止多线程异常。

你的TryAdd方法显然被阻塞了,因为它正在等待一个锁(由不同的线程获取)被释放。

并发字典枚举(例如您的Where 操作)没有阻塞的原因是因为它们使用了无锁模型。

使用普通的旧字典而不是 ConcurrentDictionary 不会产生任何性能优势,因为您必须自己使用读写锁来处理锁​​定。

正如@Usr 在您的 cmets 中所说,如果您的目标是进行非阻塞处理,那么您在 multiple-writers 场景中使用单个 ConcurrentDictionary 的整个概念可能是错误的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-29
    • 1970-01-01
    • 1970-01-01
    • 2018-05-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多