ConcurrentDictionary Pitfall - 来自 GetOrAdd 和 AddOrUpdate 的委托
本文关键字:AddOrUpdate GetOrAdd Pitfall 来自 ConcurrentDictionary | 更新日期: 2023-09-27 18:33:21
ConcurrentDictionary
的文档没有明确说明,所以我想我们不能期望委托valueFactory
和updateValueFactory
同步它们的执行(分别来自 GetOrAdd(( 和 AddOrUpdate(( 操作(。
因此,我认为如果不手动实现我们自己的并发控制,也许只是在委托上使用[MethodImpl(MethodImplOptions.Synchronized)]
,我们就无法实现其中需要并发控制的资源的使用。
我说的对吗?或者ConcurrentDictionary
线程安全的事实,我们可以期望对这些委托的调用会自动同步(也是线程安全的(?
是的,你是对的,用户代表没有通过ConcurrentDictionary
同步。 如果您需要这些同步,这是您的责任。
MSDN 本身说:
另外,虽然 ConcurrentDictionary 的所有方法都是 线程安全,并非所有方法都是原子的,特别是 GetOrAdd 和 添加或更新。传递给这些方法的用户委托是 在字典的内部锁外部调用。(这样做是为了 防止未知代码阻塞所有线程。
请参阅"如何:在 ConcurrentDictionary 中添加和删除项
这是因为ConcurrentDictionary
不知道您提供的委托将执行什么操作或其性能,因此如果它试图锁定它们,它可能会真正对性能产生负面影响并破坏 ConcurrentDictionary 的值。
因此,如有必要,用户有责任同步其委托。 上面的 MSDN 链接实际上有一个很好的示例,说明它所做的保证和不做的保证。
这些委托不仅不同步,而且甚至不能保证只发生一次。事实上,每次调用 AddOrUpdate
时,它们可以多次执行。
例如,AddOrUpdate
算法如下所示。
TValue value;
do
{
if (!TryGetValue(...))
{
value = addValueFactory(key);
if (!TryAddInternal(...))
{
continue;
}
return value;
}
value = updateValueFactory(key);
}
while (!TryUpdate(...))
return value;
请注意两件事。
- 无需同步委托的执行。
- 委托可能会被多次执行,因为它们是在循环中调用的。
所以你需要确保你做两件事。
- 为委托提供您自己的同步。
- 确保委托没有任何副作用,这些副作用取决于它们的执行次数。