c# - ConcurrentDictionary 线程安全替代方案中的 AddOrUpdate 方法
问题描述
根据此链接ConcurrentDictionary 中的 AddOrUpdate 线程是否安全?来自本页https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx的“备注”部分。它说
“但是,这些方法的委托是在锁外调用的,以避免在锁下执行未知代码可能出现的问题。因此,这些委托执行的代码不受操作原子性的影响。”
问题是我在我的代码中广泛使用它并意识到我有一个潜在的非常讨厌的错误(我的理解一直是错误的)......因为我使用下面的方式我没想到可以在同时覆盖内部字典:
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;
}
}
}
我有一个进一步的挑战,天真地把锁放在适当的位置可能会导致热点,上面的类被广泛用于从 via 读取GetForHandler()
并偶尔写入(通过AddProducer()
method.
通过大量读取和偶尔写入的高性能来确保这是线程安全的最佳方法是什么?
解决方案
我建议使用嵌套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
类真正线程安全,而不会牺牲其效率。
推荐阅读
- r - 获得系列中的第一场比赛,R
- weebly - Weebly:点击“管理”按钮后重定向到错误的网址
- python - 在 Kivy 中使用 SVG
- redis - Redis 在密钥过期时更新排序集
- flutter - 找不到正确的提供者
在这个 AddSupervisor 小部件上方 - excel - Excel 给出错误的总和
- javascript - 从递归中获取总数
- javascript - Setter 和 value 属性无法正常工作
- java - java - 如何解决wildcardQuery elasticsearch java中的空格问题?
- c# - button.OnClick 监听器触发两次