为什么 ConcurrentDictionary 有 AddOrUpdate 和 GetOrAdd,而 Dictionary 没有?

Po-*_*ang 5 .net c# dictionary concurrentdictionary

在 .NET Framework 中,有DictionaryConcurrentDictionary. 这些提供诸如Add,Remove等方法...

我知道当我们设计一个多线程程序时,我们使用ConcurrentDictionary来代替Dictionary线程安全。

我不知道为什么ConcurrentDictionaryAddOrUpdateGetOrAdd和类似的方法,同时Dictionary也没有。

我们总是喜欢下面的代码从 a 获取对象Dictionary

var dict = new Dictionary<string, object>();
object tmp;
if (dict.ContainsKey("key"))
{
       tmp = dict["key"];
}
else
{
       dict["key"] = new object();
       tmp = new object();
}
Run Code Online (Sandbox Code Playgroud)

但是在使用时ConcurrentDictionary,类似的代码只有一行。

var conDict = new ConcurrentDictionary<string, object>();
var tmp = conDict.GetOrAdd("key", new object());
Run Code Online (Sandbox Code Playgroud)

我希望 .NET 有这些方法,但为什么没有呢?

Pat*_*man 6

因为这样的方法是:

  1. 在并发上下文中工作的最低要求。你不能分裂GetAdd在两个独立的步骤没有锁定,而且还产生正确的结果。

  2. 当实现 for 时Dictionary<TKey, TValue>,它隐含地表明了某种程度的线程安全,好像Dictionary<TKey, TValue>可以以正确的方式处理这个。它不能,所以它只是没有实现。这并不能阻止您使用扩展方法来做类似的事情。

     public static TValue GetOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, Func<TKey, TValue> valueGenerator)
     {
         //
         // WARNING: this method is not thread-safe and not intended as such.
         //
         if (!dict.TryGetValue(key, out TValue value))
         {
             value = valueGenerator(key);
    
             dict.Add(key, value);
         }
    
         return value;
     }
    
    Run Code Online (Sandbox Code Playgroud)

  • 实际上,对于字典来说,在其中包含该方法实际上可能是有意义的,不是从线程安全的角度而是从优化的角度来看。字典已经计算出它期望该项目位于哪个桶中,而不是哪个桶中,然后它可以简单地将项目直接放入该桶中。使用 tryget+add 时,它必须对密钥进行两次哈希处理。 (2认同)