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

7
在.NET Framework中,有`Dictionary`和`ConcurrentDictionary`。它们提供了像`Add`、`Remove`等方法。
当我们设计多线程程序时,使用`ConcurrentDictionary`来替换`Dictionary`以实现线程安全。
我想知道为什么`ConcurrentDictionary`具有`AddOrUpdate`、`GetOrAdd`等类似的方法,而`Dictionary`没有。
通常我们使用以下代码从`Dictionary`中获取对象:
var dict = new Dictionary<string, object>();
object tmp;
if (dict.ContainsKey("key"))
{
       tmp = dict["key"];
}
else
{
       dict["key"] = new object();
       tmp = new object();
}

但是当使用ConcurrentDictionary时,类似的代码只需要一行。

var conDict = new ConcurrentDictionary<string, object>();
var tmp = conDict.GetOrAdd("key", new object());

我期望.NET会有那些方法,但为什么它没有呢?


4
ConcurrentDictionary有这些方法是因为它们可以防止竞态条件,而Dictionary则不需要,因为它本质上无法保证线程安全。 - Lasse V. Karlsen
好的,所以 .Net 提供了这些方法来确保开发过程中的安全。谢谢。 - Po-Sen Huang
1个回答

7

因为这些方法具有以下特点:

  1. A bare minimum for working in a concurrent context. You can't split the Get and Add in two separate steps without locking, and still yield correct results.

  2. When implemented for Dictionary<TKey, TValue>, it implicitly indicates some level of thread-safety, as if Dictionary<TKey, TValue> can handle this in a correct matter. It can't, so it is just not implemented. That doesn't stop you for making an extension method to do something similar.

     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;
     }
    

2
实际上,对于一个字典而言,在方法中加入这个操作其实是有意义的,不是从线程安全的角度,而是从优化的角度来看。因为字典已经确定了这个项所在的桶,但如果使用tryget+add的话,需要再次计算该键的哈希值。 - Lasse V. Karlsen
1
从那个角度来看是这样,但在这方面,它只是一个编码的性能优化。我认为.NET在这方面需要做一些严肃的工作。@LasseVågsætherKarlsen - Patrick Hofman
此外,当引入 Dictionary<TKey, TValue> 时,还没有 lambda 这样的东西。如果您总是需要传递已创建的实例而不是 Func<>,那么效率可能会降低。 - Patrick Hofman
@LasseV.Karlsen 因此,如果您真的需要,构建“更快”的字典类很容易。我一直想知道为什么明显的成员被省略了。 - Frank Hileman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接