按照此页面“备注”部分中的Is AddOrUpdate thread safe in ConcurrentDictionary?链接https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx。它说
"However, delegates for these methods are called outside the locks to avoid the problems that can arise from executing unknown code under a lock. Therefore, the code executed by these delegates is not subject to the atomicity of the operation."
问题是我在我的代码中广泛使用了该代码,并意识到我有一个潜在的非常讨厌的错误(我的理解一直以来都是错误的)...因为在使用下面的方式时,我没想到可以在同时覆盖内部字典:
internal class HandlerProducers
{
readonly ConcurrentDictionary<Type, Dictionary<Type, InstanceProducer>> handlerProducers
= new ConcurrentDictionary<Type, Dictionary<Type, InstanceProducer>>();
public void AddProducer(Type notificationType, Type concreteType, InstanceProducer producer)
{
this.handlerProducers
.AddOrUpdate(
notificationType,
(key) => new Dictionary<Type, InstanceProducer> { { concreteType, producer } },
(key, dictionary) => { dictionary.Add(concreteType, producer); return dictionary; });
}
public IEnumerable<InstanceProducer> GetForHandler(Type notificationHandlerType)
{
if(this.handlerProducers.TryGetValue(notificationHandlerType, out var dict))
{
foreach (var kvp in dict)
yield return kvp.Value;
}
}
}
我还有一个挑战,就是天真地将锁置于适当位置可能会引起热点,以上类广泛用于通过GetForHandler()
进行读取,并且有时会被写入(通过AddProducer()
方法)。通过具有大量读取和偶发写入的性能设计人员,确保这是线程安全的最佳方法是什么?
最佳答案
我建议使用嵌套的ConcurrentDictionary
结构:
readonly ConcurrentDictionary<Type, ConcurrentDictionary<Type, InstanceProducer>> handlerProducers
= new ConcurrentDictionary<Type, ConcurrentDictionary<Type, InstanceProducer>>();
然后,您可以像这样实现AddProducer
方法:public void AddProducer(Type notificationType, Type concreteType,
InstanceProducer producer)
{
ConcurrentDictionary<Type, InstanceProducer> innerDict =
this.handlerProducers.GetOrAdd(notificationType,
_ => new ConcurrentDictionary<Type, InstanceProducer>());
if (!innerDict.TryAdd(concreteType, producer))
throw new InvalidOperationException(
$"{notificationType}.{concreteType} already exists.");
}
方法GetForHandler
无需修改。此实现将使
HandlerProducers
类真正具有线程安全性,而不会牺牲其效率。
关于c# - ConcurrentDictionary线程安全替代方案中的AddOrUpdate方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63314627/