【问题标题】:AddOrUpdate method of ConcurrentDictionary always do lock (not skip if values equals)ConcurrentDictionary 的 AddOrUpdate 方法总是锁定(如果值相等则不跳过)
【发布时间】:2019-10-03 04:56:15
【问题描述】:

我在Reference Source 中阅读了 AddOrUpdate 方法的代码,发现如果 oldValue 和 newValue 相等,该方法无论如何都会进行更新。这是真的吗?我理解正确吗?因为它,该方法总是会锁定。

更新: 当我看到 AddOrUpdate 方法的代码时,我想“如果 oldValue 等于 newValue,为什么我们需要使用带锁的 TryUpdate?我们可以检查相等并返回如果值等于”因为它我问这个问题。

我明白为什么这个方法总是更新或添加,而不检查 oldValue 和 newValue 是否相等。 TValue 是对象,如果不覆盖equals方法,我们无法比较它。

因此,如果您希望 AddOrUpdate 在 oldValue 和 newValue 相等时不锁定 ConcurrentDictionary,则需要使用您的类创建方法。我不知道您如何使用泛型来做到这一点。

【问题讨论】:

  • 什么是“做锁”?
  • 因为方法 TryAdd 和方法 TryUpdate 会锁定。在 AddOrUpdate 方法中始终使用 TryAdd 或 TryUpdate。
  • 是的,它总是 lock ,但是你为什么要问这个问题呢?
  • 您提问的目的是什么? Did i understand it correct,谁知道你是怎么理解的?
  • 因为方法本身不是原子的,并且用于比较的旧值此时可能是陈旧的。

标签: c# concurrentdictionary


【解决方案1】:

您应该在更新前使用ContainsKey

ContainsKey 调用 TryGetValueline 509 读取:

 // We can get away w/out a lock here. 

:)

【讨论】:

  • 但 ContainsKey 不使用 newValue 检查键的值。
【解决方案2】:

我认为可能可以做到这一点?先用IEqualityComparer<TValue>比较。

public TValue AddOrUpdate<TArg>(TKey key, Func<TKey, TArg, TValue> addValueFactory, Func<TKey, TValue, TArg, TValue> updateValueFactory, TArg factoryArgument)
{
      // key exists, try to update
      if (TryGetValue(key, out oldValue))
      {

           TValue newValue = updateValueFactory(key, oldValue, factoryArgument);
           IEqualityComparer<TValue> valueComparer = EqualityComparer<TValue>.Default;
           if (valueComparer.Equals(oldValue, newValue))
           { return newValue; }
        }
        //...
    }

【讨论】:

  • 它是有缺陷的,因为没有考虑并发性。
  • @DmytroMukalov 我的错,需要锁定@@
【解决方案3】:

我明白为什么这个方法总是更新或添加,而不检查 oldValue 和 newValue 是否相等。 TValue 是对象,如果不覆盖equals方法,我们无法比较它。

因此,如果您希望 AddOrUpdate 在 oldValue 和 newValue 相等时不锁定 ConcurrentDictionary,则需要使用您的类创建方法。我不知道您如何使用泛型来做到这一点。

【讨论】:

  • 该方法将 AddUpdate。这两个操作都需要锁定。你的问题和答案都不清楚。
  • 这看起来不是答案,而是问题的一部分。请考虑更新您的问题,而不是产生新的帖子,这可能会在未来让读者感到困惑。
  • 当我看到 AddOrUpdate 方法的代码时,我想“如果 oldValue 等于 newValue,为什么我们需要使用带锁的 TryUpdate?我们可以检查相等并在值相等时返回”因为它我问了这个问题。
  • @КонстантинЗолин 你不能或者更确切地说你不能安全地做到这一点。您必须使值更新的整个过程原子化(例如,通过将其包装到 lock 中)这将完全否定 ConcurrentDictionary 的好处。
  • @DmytroMukalov 例如,我有 ConcurrentDictionary。为什么我不能使用它: if (TryGetValue(key, out oldValue)) { if (oldValue != newValue) TryUpdate(key, newValue, oldValue); } 其他 { TryAdd(key, newValue) } 。为什么我需要将其作为原子(锁定)?我只看到一个问题,如果它是泛型方法 oldValue 和 newValue 是对象,我们不能将它等于 int 值。
猜你喜欢
  • 2012-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多