Mar*_*rko 4 c# multithreading concurrentdictionary
如果我有以下代码:
var dictionary = new ConcurrentDictionary<int, HashSet<string>>();
foreach (var user in users)
{
if (!dictionary.ContainsKey(user.GroupId))
{
dictionary.TryAdd(user.GroupId, new HashSet<string>());
}
dictionary[user.GroupId].Add(user.Id.ToString());
}
Run Code Online (Sandbox Code Playgroud)
将项添加到HashSet本身就是线程安全的行为是因为HashSet是并发字典的值属性吗?
否.将容器放入线程安全的容器中不会使内部容器线程安全.
dictionary[user.GroupId].Add(user.Id.ToString());
Run Code Online (Sandbox Code Playgroud)
从ConcurrentDictionary中检索HashSet之后调用它.如果同时从两个线程查找此GroupId,则会以奇怪的故障模式破坏您的代码.我看到我的一个队友犯了一个错误,就是没有锁定他的套装,结果并不漂亮.
这是一个合理的解决方案.我自己会做一些不同的事情,但这更接近你的代码.
if (!dictionary.ContainsKey(user.GroupId)
{
dictionary.TryAdd(user.GroupId, new HashSet<string>());
}
var groups = dictionary[user.GroupId];
lock(groups)
{
groups.Add(user.Id.ToString())
}
Run Code Online (Sandbox Code Playgroud)
不,集合(字典本身)是线程安全的,而不是你放入其中的任何内容。您有几个选择:
正如@TheGeneral提到的那样使用AddOrUpdate:
dictionary.AddOrUpdate(user.GroupId, new HashSet<string>(), (k,v) => v.Add(user.Id.ToString());
Run Code Online (Sandbox Code Playgroud)使用并发集合,例如ConcurrentBag<T>:
ConcurrentDictionary<int, ConcurrentBag<string>>
Run Code Online (Sandbox Code Playgroud)每当您构建字典时,就像在代码中一样,您最好尽可能少地访问它。想想这样的事情:
var dictionary = new ConcurrentDictionary<int, ConcurrentBag<string>>();
var grouppedUsers = users.GroupBy(u => u.GroupId);
foreach (var group in grouppedUsers)
{
// get the bag from the dictionary or create it if it doesn't exist
var currentBag = dictionary.GetOrAdd(group.Key, new ConcurrentBag<string>());
// load it with the users required
foreach (var user in group)
{
if (!currentBag.Contains(user.Id.ToString())
{
currentBag.Add(user.Id.ToString());
}
}
}
Run Code Online (Sandbox Code Playgroud)
ConcurrentDictionary<int, ConcurrentDictionary<string, string>>, 并关心内部集合中的键或值。| 归档时间: |
|
| 查看次数: |
619 次 |
| 最近记录: |