当前位置: 首页 > news >正文

C#开发——ConcurrentDictionary集合

        ConcurrentDictionary<TKey, TValue>   是 C# 中一个专为多线程场景设计的线程安全字典集合,位于   System.Collections.Concurrent   命名空间中。它允许多个线程同时对字典进行读写操作,而无需额外的同步措施。

一、集合特征

此集合有如下特征:

1. 线程安全:

•   ConcurrentDictionary   内部使用了细粒度的锁定机制(如分段锁)或无锁技术,确保在多线程环境中的操作安全。

• 绝大多数操作(如   TryAdd  、  TryUpdate  、  TryRemove  )都是线程安全的。

2. 高性能:

• 由于采用了细粒度锁定或无锁技术,  ConcurrentDictionary   在高并发场景下通常比普通字典(如   Dictionary<TKey, TValue>  )具有更好的性能。

3. 灵活的操作方法:

• 提供了多种线程安全的方法,如   TryAdd  、  TryUpdate  、  TryRemove   和   GetOrAdd   等。这些方法在操作失败时不会抛出异常,而是返回一个布尔值来指示操作是否成功。

• 特别需要注意的是,  AddOrUpdate   和   GetOrAdd   方法中涉及委托的部分并不是完全原子性的,需要开发者特别注意。

4. 允许空值:• 与普通   Dictionary   不同,  ConcurrentDictionary   允许键或值为   null  。

        使用示例以下是一个简单的   ConcurrentDictionary   使用示例:

using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        // 创建一个线程安全的 ConcurrentDictionary 实例
        ConcurrentDictionary<int, string> concurrentDictionary = new ConcurrentDictionary<int, string>();

        // 使用 TryAdd 方法添加键值对
        concurrentDictionary.TryAdd(1, "one");
        concurrentDictionary.TryAdd(2, "two");

        // 使用 TryGetValue 方法获取值
        if (concurrentDictionary.TryGetValue(1, out string value))
        {
            Console.WriteLine($"Value for key 1: {value}");
        }

        // 使用 AddOrUpdate 方法更新或添加键值对
        concurrentDictionary.AddOrUpdate(1, "new one", (key, oldValue) => "updated one");

        // 使用 TryRemove 方法移除键值对
        concurrentDictionary.TryRemove(2, out _);

        // 在多线程环境中操作 ConcurrentDictionary
        Parallel.For(3, 10, i =>
        {
            concurrentDictionary.TryAdd(i, i.ToString());
        });

        // 遍历并输出 ConcurrentDictionary 中的所有元素
        foreach (var item in concurrentDictionary)
        {
            Console.WriteLine($"Key: {item.Key}, Value: {item.Value}");
        }
    }
}

二、适用场景

• 多线程数据共享:当多个线程需要同时访问和修改同一个字典时,  ConcurrentDictionary   是最合适的选择。

• 高并发场景:在需要高性能并发访问的场景中,  ConcurrentDictionary   的细粒度锁定机制可以显著减少锁竞争。注意事项• 委托方法的线程安全性:  AddOrUpdate   和   GetOrAdd   方法中涉及委托的部分并不是完全原子性的,因此需要开发者确保委托操作的线程安全性。

• 性能优化:虽然   ConcurrentDictionary   本身性能较高,但在极端高并发场景下,仍需根据实际需求进行性能测试和优化。

总之,  ConcurrentDictionary   是一个强大的线程安全字典集合,适用于多线程和高并发场景,能够有效解决普通字典在多线程环境下的线程安全问题。

三、高性能

  ConcurrentDictionary<TKey, TValue>   的高性能主要体现在以下几个方面:

1. 细粒度锁定与无锁算法 

        ConcurrentDictionary   内部采用了细粒度锁定(分段锁)或无锁算法(Lock-free),这使得多个线程可以同时对字典进行操作,而不会出现严重的竞争条件。例如,它使用了 CAS(Compare and Swap)操作来确保线程安全,这种无锁机制减少了线程间的同步开销。

2. 动态扩容

        ConcurrentDictionary   支持动态扩容,能够根据实际负载自动调整内部数据结构的大小。这种动态调整能力使得它能够适应不同的并发场景,避免因固定容量导致的性能瓶颈。

3. 高效的哈希表实现

        ConcurrentDictionary   内部基于哈希表实现,使用散列函数将键映射到存储位置,并通过链表或红黑树处理冲突。这种数据结构支持常数时间复杂度(O(1))的添加、查找和修改操作,从而提高了整体性能。

4. 适用于多生产者和多消费者场景

        ConcurrentDictionary   的设计目标是在多生产者和多消费者环境中提供高效的并发访问。它允许多个线程同时对字典进行读写操作,而无需额外的同步机制。

5. 减少锁的开销

        与传统的线程安全集合(如通过   lock   实现的同步机制)相比,  ConcurrentDictionary   通过优化的并发算法减少了锁的使用频率和范围。这种设计不仅提高了性能,还降低了死锁的风险。

6. 灵活的操作方法

        ConcurrentDictionary   提供了多种线程安全的操作方法,如   TryAdd  、  TryUpdate   和   TryRemove  ,这些方法在操作失败时不会抛出异常,而是返回布尔值,从而避免了异常处理的开销。

        总结  ConcurrentDictionary   的高性能主要得益于其细粒度锁定或无锁算法、动态扩容能力、高效的哈希表实现以及对多生产者和多消费者场景的优化。这些特性使其在高并发场景下表现出色,能够显著提高多线程应用程序的性能。

四、常用属性

Count:获取字典中键值对的数量。

IsEmpty:判断字典是否为空。

Keys:获取字典中所有键的集合(返回   IEnumerable<TKey>  )。

Values:获取字典中所有值的集合(返回   IEnumerable<TValue>  )。

实例代码:

var dict = new ConcurrentDictionary<int, string>();
dict.TryAdd(1, "one");
dict.TryAdd(2, "two");
//Count 属性
Console.WriteLine(dict.Count); // 输出:2


var dict = new ConcurrentDictionary<int, string>();
//IsEmpty 属性
Console.WriteLine(dict.IsEmpty); // 输出:True
dict.TryAdd(1, "one");
Console.WriteLine(dict.IsEmpty); // 输出:False

var dict = new ConcurrentDictionary<int, string>
{
    {1, "one"},
    {2, "two"}
};
//Keys 属性
foreach (var key in dict.Keys)
{
    Console.WriteLine(key); // 输出:1, 2
}

var dict = new ConcurrentDictionary<int, string>
{
    {1, "one"},
    {2, "two"}
};
//Values 属性
foreach (var value in dict.Values)
{
    Console.WriteLine(value); // 输出:"one", "two"
}

var dict = new ConcurrentDictionary<int, string>();
bool added = dict.TryAdd(1, "one");
Console.WriteLine(added); // 输出:True
added = dict.TryAdd(1, "one");
Console.WriteLine(added); // 输出:False

五、常用方法

TryAdd(TKey key, TValue value):尝试将键值对添加到字典中。如果键已存在,则返回   false  。

TryUpdate(TKey key, TValue newValue, TValue comparisonValue):尝试更新指定键的值。只有当当前值等于   comparisonValue   时,才会更新为   newValue 。

TryRemove(TKey key, out TValue value):尝试从字典中移除指定键的键值对,并返回其值。

 GetOrAdd(TKey key, TValue value):如果字典中不存在指定键,则添加键值对并返回值;如果已存在,则返回已有的值。

GetOrAdd(TKey key, Func<TKey, TValue> valueFactory):如果字典中不存在指定键,则通过   valueFactory   动态生成值并添加到字典中。

AddOrUpdate(TKey key, TValue addValue, Func<TKey, TValue, TValue> updateValueFactory):如果键不存在,则添加   addValue  ;如果键已存在,则通过   updateValueFactory   更新值。

ContainsKey(TKey key):判断字典中是否包含指定键。

Clear():清空字典中的所有键值对。

参考代码:

var dict = new ConcurrentDictionary<int, string>();
//TryAdd()方法
bool added = dict.TryAdd(1, "one");
Console.WriteLine(added); // 输出:True
added = dict.TryAdd(1, "one");
Console.WriteLine(added); // 输出:False

var dict = new ConcurrentDictionary<int, string>
{
    {1, "one"}
};
//TryUpdate()方法
bool updated = dict.TryUpdate(1, "new one", "one");
Console.WriteLine(updated); // 输出:True
updated = dict.TryUpdate(1, "updated one", "old one");
Console.WriteLine(updated); // 输出:False

var dict = new ConcurrentDictionary<int, string>
{
    {1, "one"}
};
//TryRemove()方法
bool removed = dict.TryRemove(1, out string value);
Console.WriteLine(removed); // 输出:True
Console.WriteLine(value); // 输出:"one"


var dict = new ConcurrentDictionary<int, string>();
//GetOrAdd()方法
string value = dict.GetOrAdd(1, "one");
Console.WriteLine(value); // 输出:"one"
value = dict.GetOrAdd(1, "new one");
Console.WriteLine(value); // 输出:"one"(未更新)

var dict = new ConcurrentDictionary<int, string>();
//GetOrAdd()方法
string value = dict.GetOrAdd(1, key => $"Value for {key}");
Console.WriteLine(value); // 输出:"Value for 1"

var dict = new ConcurrentDictionary<int, string>();
//AddOrUpdate()方法
dict.AddOrUpdate(1, "one", (key, oldValue) => $"Updated {oldValue}");
Console.WriteLine(dict[1]); // 输出:"one"
dict.AddOrUpdate(1, "new one", (key, oldValue) => $"Updated {oldValue}");
Console.WriteLine(dict[1]); // 输出:"Updated one"

var dict = new ConcurrentDictionary<int, string>
{
    {1, "one"}
};
//ContainsKey()方法
bool contains = dict.ContainsKey(1);
Console.WriteLine(contains); // 输出:True

var dict = new ConcurrentDictionary<int, string>
{
    {1, "one"}
};
//Clear()方法
dict.Clear();
Console.WriteLine(dict.Count); // 输出:0

其他方法

GetEnumerator():返回一个枚举器,用于遍历字典中的键值对。

ToDictionary():将ConcurrentDictionary转换为普通的Dictionary<TKey, TValue>。

总结

ConcurrentDictionary<TKey, TValue> 提供了丰富的线程安全方法,适用于多线程环境。常用的方法如   TryAdd、TryUpdate、TryRemove、GetOrAdd和AddOrUpdate等,能够灵活地处理并发操作,同时避免了传统字典在多线程场景下的线程安全问题。

相关文章:

  • 华为认证考试证书下载步骤(纸质+电子版)
  • docker安装register私库
  • 详解golang的Gengine规则引擎
  • 【排序算法】堆排序详解
  • 基于 SpringBoot 的 “电影交流平台小程序” 系统的设计与实现
  • 推送项目 之 解决冲突
  • Claude 3.7 Sonnet 泄露,Anthropic 最先进 AI 模型即将在 AWS Bedrock 上首次亮相
  • 【NLP 26、实践 ⑥ 引入bert,判断文本中是否有特定字符出现】
  • 深入理解 Redis 设计与集群管理
  • JavaSE学习笔记26-集合(Collection)
  • Unity百游修炼(1)——FootBall详细制作全流程
  • 大模型语料库的构建过程 包括知识图谱构建 垂直知识图谱构建 输入到sql构建 输入到cypher构建 通过智能体管理数据生产组件
  • 【前端基础】Day 1 HTML
  • 【Qt】桌面应用开发 ------ 绘图事件和绘图设备 文件操作
  • 渗透小记--Docker Registry未授权访问
  • PHP_最新版PTCMS小说聚合网站系统源码+会员收费机制+深度SEO优化带自动采集+采集规则+安装教程
  • Web刷题之PolarDN(中等)
  • mysql 学习17 SQL 锁
  • Webpack打包优化
  • 浅谈 Redis 主从复制原理(二)
  • 广东省深圳市公司/网站优化方案范文
  • 公众号里的功能怎么开发/网站优化seo方案
  • python基础教程百度网盘/google seo整站优化
  • 南宁网站制作哪家好/互联网营销师证书查询入口
  • 饿了么网站开发/竞价推广营销
  • 包头网站设计推广/旺道seo推广有用吗