C# ConcurrentDictionary对象-通过不同线程进行读写
我想在我的应用程序中使用ConcurrentDictionary,但首先我需要确保我正确理解它的工作原理。在我的应用程序中,我将有一个或多个线程写入或删除字典。并且,我将有一个或多个从字典中读取的线程。可能,所有这些都是同时发生的 ConcurrentDictionary的实现负责实现这一点所需的所有锁定,而我不需要提供自己的锁定,这对吗?换句话说,如果一个线程正在向字典写入或从字典中删除,那么一个读取线程(或另一个写入线程)将被阻止,直到更新或删除完成 非常感谢 换句话说,如果一个线程正在向字典写入或从字典中删除,那么一个读取线程(或另一个写入线程)将被阻止,直到更新或删除完成 我不相信它会堵塞——它只是安全的。不会有任何腐败——你只需要在读是否看到写方面进行竞争 从a:C# ConcurrentDictionary对象-通过不同线程进行读写,c#,multithreading,thread-safety,C#,Multithreading,Thread Safety,我想在我的应用程序中使用ConcurrentDictionary,但首先我需要确保我正确理解它的工作原理。在我的应用程序中,我将有一个或多个线程写入或删除字典。并且,我将有一个或多个从字典中读取的线程。可能,所有这些都是同时发生的 ConcurrentDictionary的实现负责实现这一点所需的所有锁定,而我不需要提供自己的锁定,这对吗?换句话说,如果一个线程正在向字典写入或从字典中删除,那么一个读取线程(或另一个写入线程)将被阻止,直到更新或删除完成 非常感谢 换句话说,如果一个线程正在向字
ConcurrentDictionary
在添加或更新字典中的数据时使用细粒度锁定,但对于读取操作,它完全没有锁定。通过这种方式,它针对从字典中读取是最频繁操作的场景进行了优化
当前的实现混合使用了条带锁(我在昨天的一次会议上回答某人时建议的技术),并且非常认真地思考操作不可能导致并发操作出现问题或由并发操作导致问题的情况(有很多,但是如果你使用它们,你必须非常确定) 因此,如果同时在并发字典上执行多个操作,则可以执行以下每个操作:
ConcurrentDictionary
上的单个方法可以满足一些需要对Dictionary
进行两次调用的常见情况(GetOrAdd
和AddOrUpdate
使用Dictionary
执行两个调用,这样它们就可以原子化完成-不过请注意,某些重载中涉及的Func
可能会被多次调用)
因此,ConcurrentDictionary
没有额外的危险,因此您应该选择以下选项:
如果您必须锁定与ConcurrentDictionary
提供的内容不匹配的某些批操作,例如:
lock(lockObj)
{
var test = dict[key1];
var test2 = dict[key2];
if(test < test2 && test2 < dict[key3] && SomeOtherBooleanProducer())
dict[key4] = SomeFactoryCall(key4);
}
锁(lockObj)
{
var测试=dict[key1];
var test2=dict[key2];
if(test
然后您必须锁定ConcurrentDictionary
,虽然可能有一种方法可以将其与它提供的并发支持结合起来,但可能不会,所以只需使用带有锁的Dictionary
否则,它将归结为并发命中的数量。如果你大部分时间只会有一个线程命中字典,但你需要防止并发访问的可能性,那么你肯定应该使用带锁的字典。如果你会有六个或更多线程无法访问字典线程正在命中字典,那么您肯定应该选择ConcurrentDictionary
(如果它们很可能命中相同数量的键,那么请查看我的版本,因为这是一种性能更好的情况)
很难说“少”线程和“多”线程之间的中间点在哪里。我想说的是,如果定期有两个以上的线程,那么使用ConcurrentDictionary
。如果没有其他问题,在项目的整个生命周期中,并发性的需求往往会增加,而不是减少
编辑:为了回答您给出的关于一个作者和一个读者的特定案例,根本不会有任何阻塞,因为这是安全的,原因大致相同,即多个读者和一个作者在哈希表上是安全的,尽管ConcurrentDictionary
在几个方面都超出了这一点。谢谢。听起来好像是有可能的允许“脏读”(使用SQL术语)。对于我的应用程序,这是可以的。我想如果我想完全避免这种可能性,我不会使用ConcurrentDictionary,我会使用非并发字典并实现我自己的锁定。@RandyMinder:不,我认为脏读是不可能的-即使锁定了,你仍然会有数据竞争,不是吗?要么读取发生在写入之前e、 或者它发生在之后。所有的无锁意味着在读取之前开始的写入在读取之前仍然看不到。我相信在读取开始之前结束的写入应该总是可见的。我可以很容易地对此进行测试以找出答案。但是,就我而言,这不是问题。ConcurrentDictionary的实现方式将