并发字典正确用法


84

我认为这是正确使用并发字典的意思吗?

private ConcurrentDictionary<int,long> myDic = new ConcurrentDictionary<int,long>();

//Main thread at program startup

for(int i = 0; i < 4; i++)
{
  myDic.Add(i, 0);
}

//Seperate threads use this to update a value

myDic[InputID] = newLongValue;

我没有锁等,并且即使多个线程可能试图执行相同操作,也只是在更新字典中的值。


2
这取决于-是否newLongValue取决于先前的值myDic[InputID]
Damien_The_Unbeliever

3
您应避免直接myDic[InputID]在比赛条件下通过钥匙进入。您应该尝试GetOrAdd
Olivier Albertini

3
@OlivierAlbertini,将myDic[InputID]其用作左值时,我认为不会引起任何问题。GetOrAdd不是正确的替换,因为仅当值不存在时才添加。我们可以改为使用AddOrUpdate在字典中添加/更新相同的值。
贾廷·桑格维

Answers:


75

这取决于您所说的线程安全性。

从MSDN-如何:从ConcurrentDictionary添加和删除项目

ConcurrentDictionary<TKey, TValue>设计用于多线程方案。您不必在代码中使用锁即可添加或删除集合中的项目。但是,一个线程总是有可能检索一个值,而另一个线程总是可以通过给同一个键一个新值来立即更新集合。

因此,可能会在字典中获得不一致的项目值视图


2
那是一个有趣的观点!在那种情况下,您还会使用锁吗?
乔恩

@Jon-这取决于您的应用程序,是否可以。但是我要说的是,如果您想要项目的一致视图,则需要将项目的每次读取和更新都包装在一个锁中。
奥德

12
我认为这不是医生所说的。不一致与视图包含的内容有关,如果视图只是值,则它是完全一致的。只要获得键的值,字典中键的值就可能改变。这与DateTime.Now值不一致。
乔治·马夫里察斯基斯

4

找出此问题的最佳方法是查看MSDN文档。

对于ConcurrentDictionary,页面为http://msdn.microsoft.com/zh-cn/library/dd287191.aspx

在线程安全部分,声明为“ ConcurrentDictionary(Of TKey,TValue)的所有公共成员和受保护成员都是线程安全的,并且可以在多个线程中同时使用。”

因此,从并发角度来看,您还可以。


2

你是对的。

那和在一个线程上枚举字典而在另一个线程上更改字典的可能性是该类存在的唯一手段。


9
我要补充的是,这里是有关如何以及何时使用的有用信息ConcurrentDictionary
alex.b

1

就我而言,这取决于我更喜欢​​使用此方法。

ConcurrentDictionary<TKey, TValue>.AddOrUpdate Method (TKey, Func<TKey, TValue>, Func<TKey, TValue, TValue>);

有关方法用法的详细信息,请参见MSDN Library

用法示例:

results.AddOrUpdate(
  Id,
  id => new DbResult() {
     Id = id,
     Value = row.Value,
     Rank = 1
  },
  (id, v) =>
  {
     v.Rank++;
     return v;
  });

2
仅供参考:“当您提供一个值工厂方法(给GetOrAdd和AddOrUpdate方法)时,它实际上可以运行并在其后丢弃结果(因为其他一些线程赢得了比赛)。” 此处了解
keremispirli

是的,您是对的,如“在不同线程上同时调用AddOrUpdate时,addValueFactory可能会被多次调用,但它的键/值对可能不会在每次调用时都添加到字典中”中所述。因此,您需要确保不会生成多个持久对象。
2016年

并且,如果您需要更新内容而不是完全更改存储的对象(例如,更改先前添加的对象的属性),则此方法很有用,否则,您需要使用锁或其他同步方法。
Onur 2013年

1

请注意:不能证明使用带有线性循环的ConcurrentDicitonary对象是合理的。最好的替代方法是按照下面的示例,遵循Oded使用Parallelism提到的Microsoft文档的建议:

Parallel.For(0, 4, i => 
{
   myDic.TryAdd(i, 0);
});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.