将不同的值添加到并发字典内的列表中

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 要完全线程安全,我需要创建一个 ConcurrentDictionary> 来代替? 是的。或者更好ConcurrentDictionary&lt;string, ConcurrentQueue&lt;decimal&gt;&gt;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) 不是原子的,它会引入竞争条件,并且可能会影响应用程序的正确性。

【讨论】:

以上是关于将不同的值添加到并发字典内的列表中的主要内容,如果未能解决你的问题,请参考以下文章

给定一个字符串列表,如果任何值等于列表中的值,我想将字典的值添加到新字典中[重复]

添加到同一个字典的不同生成器返回相同的值

如何将文本输入值添加到kivy python中字典中的值?

如何将字典项分别添加到 SwiftUI 列表中

如何在创建列表时将列表存储在字典中,然后将其清除然后用于具有不同值的下一个键?

Python ❀ 字典