【发布时间】:2013-12-05 16:05:00
【问题描述】:
我有一个基于字符串生成东西的类:
string Produce(string key);
结果被缓存,所以它只产生一个。现在我想锁定生产方法。我只想要锁定钥匙的方法...如果另一个钥匙进来,它不应该锁定。
我已从 lock 切换到名为 Mutex,但我读到此方法很慢,因为 Mutex 是操作系统范围的。我将如何创建某种命名锁?
我正在使用 .Net 3.5
【问题讨论】:
我有一个基于字符串生成东西的类:
string Produce(string key);
结果被缓存,所以它只产生一个。现在我想锁定生产方法。我只想要锁定钥匙的方法...如果另一个钥匙进来,它不应该锁定。
我已从 lock 切换到名为 Mutex,但我读到此方法很慢,因为 Mutex 是操作系统范围的。我将如何创建某种命名锁?
我正在使用 .Net 3.5
【问题讨论】:
对象锁定字典的简单字符串是否有效?
object _superLock = new object();
Dictionary<string, object> _locks = new Dictionary<string, object>();
string Produce(string key) {
lock(GetLock(key)) {
// do stuff
}
}
object GetLock(string key) {
lock(_superLock) {
if (!_locks.ContainsKey(key)) {
_locks[key] = new object();
}
}
return _locks[key];
}
更新:哦,对了,ConcurrentDictionary 存在。这可能看起来像
ConcurrentDictionary<string, object> _locks = new ConcurrentDictionary<string, object>();
object GetLock(string key) {
return _locks.GetOrAdd(key, k => new object());
}
【讨论】:
GetOrAdd 返回)。
ConcurrentDictionary 让这变得非常简单:
public class Foo
{
private ConcurrentDictionary<string, object> locks =
new ConcurrentDictionary<string, object>();
public string Produce(string key)
{
lock (locks.GetOrAdd(key, new object()))
{
//TODO do whatever
return "";
}
}
}
【讨论】:
对此有相当规范的解决方案:
var cacheItems = new ConcurrentDictionary<TKey, Lazy<TValue>>();
...
TValue Get(Func<TValue> factory) {
return cacheItems.GetOrAdd(_ => new Lazy<TValue>(factory)).Value;
}
这具有以下重要属性:
可能会产生多个Lazy,但只有一个会被强制评估。
【讨论】: