【发布时间】:2017-07-15 15:05:04
【问题描述】:
我正在尝试为ConcurrentDictionary 实现扩展方法,如果键存在,则该方法在功能上从字典中获取值。如果键不存在或条件(predicate)失败,它会尝试通过调用valueFactory 来获取值。下面是我写的方法。
public static TValue ConditionalGetOrAdd<TKey, TValue>(
this ConcurrentDictionary<TKey, TValue> dictionary,
TKey key,
Func<TValue, bool> predicate,
Func<TKey, TValue> valueFactory)
{
TValue value = dictionary.GetOrAdd(key, valueFactory);
if (!predicate(value))
{
value = valueFactory(key);
dictionary[key] = value;
}
return value;
}
这里有两个问题。如果predicate 返回false,我可能会调用valueFactory 两次。这将是多余的操作。此外,整个方法不是原子的。如果一个线程在if 块内,则另一个线程不会等待它完成,然后再调用GetOrAdd 或predicate。
是否有可能在不锁定整个字典的情况下完成这项工作?就我而言,valueFactory 成本高(在内部发出 HTTP 请求),而 predicate 相当便宜。如果您有解决方案,请告诉我。如果可以达到目的,我可以修改整个方法。
【问题讨论】:
-
如果谓词检查显然不依赖于它是否在字典中,为什么不能将它移到顶部?
-
predicate将采用我们从字典中获得的value。除非我先打电话给TryGet或GetOrAdd,否则我将无法知道该值。如果我不理解评论,请告诉我。 -
啊,我现在明白了。似乎您应该只做一个普通的
TryGet()而不是GetOrAdd(),因为您不想添加它?这样,当谓词失败时,您最多只会调用一次valueFactory。 -
谢谢。那我该如何防止比赛条件。我不想在线程调用
valueFactory时,其他线程也进入相同的状态。 @john,我会看看AddOrUpdate是否适合我。给我一些时间。
标签: c# concurrency