- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我开始使用一些 .NET 3.5 代码并发现以下扩展方法用于缓存::
public static TValue GetOrAdd<TKey, TValue>(this Dictionary<TKey, TValue> @this, TKey key,Func<TKey,TValue> factory,bool useLocking)
{
TValue value;
if(!@this.TryGetValue(key,out value))
{
if (useLocking)
{
lock ((@this as ICollection).SyncRoot)
{
if (!@this.TryGetValue(key, out value))
{
@this[key] = value = factory(key);
}
}
}
else
{
@this[key] = value = factory(key);
}
}
return value;
}
有问题的缓存由字符串键作为键控,并且 useLocking = true。它总是通过这种方法访问(没有流浪 TryGetValue
)。使用 SyncRoot
也没有问题属性,因为字典是私有(private)的,没有其他地方使用它。双重锁定是危险的,因为字典在写入时不支持读取。虽然技术上还没有报告任何问题,因为产品尚未发货,但我认为这种方法会导致竞争条件。
切换Dictionary<,>
到 Hashtable
.我们将失去类型安全性,但我们将能够支持我们所追求的并发模型(1 个写入者,多个读取者)。
删除外部 TryGetValue。这样每次读取都需要获取锁。这可能对性能不利,但获取无竞争锁的成本应该相当低。
两者都很糟糕。有人有更好的建议吗?如果这是 .NET 4 代码,我会将其切换为 ConcurrentDictionary
,但我没有那个选项。
最佳答案
是的,你的怀疑是正确的;存在竞争条件,所有方法,甚至 TryGetValue
都需要在您提供的实现中的锁内。
就性能而言,您可以期待升级到 .NET4 的那一天,其中包括开箱即用的快得惊人的 ConcurrentDictionary
。在此之前,您可以在此处查看 James Michael Hare 的分析:
这些结果向我表明,.NET3.5 的最佳实现是 Dictionary
加上 ReadWriteLockSlim
,为了更好的衡量,这里有一个完整的实现:
更新:
我读错了表格,看起来 Dictionary
+ lock
比唯一的其他重要竞争者 Dictionary
+ 快一点ReadWriteLockSlim
.
关于c# - 对于 .NET 3.5,您将如何进行线程安全的获取或添加缓存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4473897/
我是一名优秀的程序员,十分优秀!