将不同的值添加到并发字典内的列表中
Posted
技术标签:
【中文标题】将不同的值添加到并发字典内的列表中【英文标题】:Adding varying values to a list inside of a Concurrent Dictionary 【发布时间】:2021-01-25 10:20:55 【问题描述】:我尝试将小数添加到 ConcurrentDictionary
内的列表中
ConcurrentDictionary<string, List<decimal>> fullList =
new ConcurrentDictionary<string, List<decimal>>();
public void AddData(string key, decimal value)
if (fullList.ContainsKey(key))
var partialList = fullList[key];
partialList.Add(value);
else
fullList.GetOrAdd(key, new List<decimal>() value );
从技术上讲,上面的代码对我有用,但它只是这样做的,因为我不知道如何使用 GetOrAdd
方法来添加和更新。我的问题是,考虑到我的更新会将一个项目添加到现有列表的末尾,我该如何使用该方法?
【问题讨论】:
请注意AddData
不是线程安全的。如果两个线程同时使用相同的key
调用它,则行为将是未定义的。 List
类不是线程安全的。
@TheodorZoulias 要完全线程安全,我需要创建一个 ConcurrentDictionaryConcurrentDictionary<string, ConcurrentQueue<decimal>>
。 ConcurrentBag
是一个非常专业的类(它只适用于混合生产者-消费者场景)。人们通常认为它是最接近线程安全List
的类型,但事实并非如此。供参考:When to use a thread-safe collection
@TheodorZoulias 我是 C# 中多线程方面的新手,正如您可能知道的那样,但我应该指定我在一个线程中添加到字典并在另一个线程中读取它,所以我我不确定这会让我进入什么场景。你仍然推荐并发队列而不是并发包吗?
是的,您的场景是纯粹的生产者-消费者,而不是混合的,因此ConcurrentQueue
的性能将优于ConcurrentBag
。混合的生产者-消费者场景,即同一线程同时充当生产者和消费者的情况非常罕见。就我个人而言,我从未见过或需要一个。
【参考方案1】:
您可以为此目的使用AddOrUpdate
方法,如下所示:
fullList.AddOrUpdate(key,
new List<decimal>() value ,
(key,list) =>
list.Add(value);
return list;
);
基本上,当key
缺失时,会创建一个新列表,其中只有一个元素value
。否则,我们将value
添加到与当前key
关联的列表中并返回该列表。
有关此方法的文档,请查看here。
【讨论】:
【参考方案2】:您正在寻找这样的东西吗?希望对您有所帮助。
ConcurrentDictionary<string, List<decimal>> fullList = new ConcurrentDictionary<string, List<decimal>>();
public void AddData(string key, decimal value)
List<decimal> list;
if (!fullList.TryGetValue(key, out list))
list = new List<decimal>();
fullList.GetOrAdd(key, list);
list.Add(value);
【讨论】:
【参考方案3】:您只需要在所有情况下调用GetOrAdd
:
public void AddData(string key, decimal value)
var partialList = fullList.GetOrAdd(key, _ => new List<decimal>());
lock (partialList) partialList.Add(value); // Lock for thread safety
当您使用 ConcurrentDictionary
时,您应该努力使用其特殊的并发 API,以强制执行操作的原子性。分两步检查和添加 (ContainsKey
+Add
) 不是原子的,它会引入竞争条件,并且可能会影响应用程序的正确性。
【讨论】:
以上是关于将不同的值添加到并发字典内的列表中的主要内容,如果未能解决你的问题,请参考以下文章
给定一个字符串列表,如果任何值等于列表中的值,我想将字典的值添加到新字典中[重复]