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

ConcurrentDictionary 详解:.NET 中的线程安全字典

什么是 ConcurrentDictionary?

ConcurrentDictionary<TKey, TValue> 是 .NET Framework 4.0+ 和 .NET Core/.NET 5+ 中引入的线程安全字典实现,位于 System.Collections.Concurrent 命名空间。它解决了多线程环境下操作字典时的同步问题,允许**多个线程同时读写字典**而无需显式加锁。

核心特性

  1. 线程安全:所有操作都是原子性的
  2. 高性能:使用细粒度锁(而非全局锁)
  3. 无锁读取:读操作通常不需要锁
  4. 原子方法:提供专门设计的线程安全方法

与普通 Dictionary 的对比

特性DictionaryConcurrentDictionary
线程安全❌ 需要手动加锁✅ 内置线程安全
读性能非常高(无锁读取)
写性能较高(细粒度锁)
并发支持需要同步机制原生支持并发
内存开销较低稍高(维护内部结构)

基本使用

// 创建实例
var concurrentDict = new ConcurrentDictionary<string, int>();// 添加元素(线程安全)
concurrentDict.TryAdd("task1", 0);
concurrentDict.TryAdd("task2", 0);// 更新元素(原子操作)
concurrentDict.AddOrUpdate("task1", key => 1,               // 添加时的工厂函数(key, oldValue) => oldValue + 1 // 更新时的函数
);// 安全获取值
if (concurrentDict.TryGetValue("task1", out int value))
{Console.WriteLine($"Task1 进度: {value}%");
}// 删除元素
concurrentDict.TryRemove("task2", out _);

关键方法详解

1. TryAdd()
bool success = concurrentDict.TryAdd("task3", 25);
// 成功添加返回 true,键已存在返回 false
2. TryUpdate()
int currentValue;
do {currentValue = concurrentDict["task1"];
} while (!concurrentDict.TryUpdate("task1", currentValue + 10, currentValue));
// 原子性更新:只有当前值等于 expectedValue 时才更新
3. AddOrUpdate()
// 添加或更新(原子操作)
int newValue = concurrentDict.AddOrUpdate("task1", key => 50,                // 添加时的工厂函数(key, oldValue) => oldValue + 10 // 更新时的函数
);
4. GetOrAdd()
// 获取或添加(原子操作)
int value = concurrentDict.GetOrAdd("task4", key => 0);
// 如果 task4 不存在,初始化为 0
5. TryRemove()
if (concurrentDict.TryRemove("task2", out int removedValue))
{Console.WriteLine($"已删除 task2,原值: {removedValue}");
}

在任务进度系统中的应用

进度存储服务实现
public class ConcurrentTaskProgressService
{private readonly ConcurrentDictionary<string, TaskProgress> _progressStore = new ConcurrentDictionary<string, TaskProgress>();public void UpdateProgress(string taskId, int completed, int total){_progressStore.AddOrUpdate(taskId,// 添加新任务id => new TaskProgress{TaskId = id,Completed = completed,Total = total,LastUpdated = DateTime.UtcNow},// 更新现有任务(id, existing) =>{existing.Completed = completed;existing.Total = total;existing.LastUpdated = DateTime.UtcNow;return existing;});}public TaskProgress GetProgress(string taskId){return _progressStore.TryGetValue(taskId, out var progress) ? progress : null;}
}public class TaskProgress
{public string TaskId { get; set; }public int Completed { get; set; }public int Total { get; set; }public DateTime LastUpdated { get; set; }public int Percentage => Total > 0 ? (Completed * 100) / Total : 0;
}

最佳实践

  1. 优先使用原子方法

    // ✅ 推荐
    dict.AddOrUpdate(key, 1, (k, v) => v + 1);// ❌ 避免(非原子操作)
    if (dict.ContainsKey(key)) {dict[key] = dict[key] + 1;
    }
    
  2. 处理工厂函数副作用

    // 工厂函数应简单无副作用
    var value = dict.GetOrAdd(key, k => {// 避免耗时操作return CalculateInitialValue(k);
    });
    
  3. 迭代时处理并发修改

    foreach (var pair in concurrentDict)
    {// 注意:迭代期间字典可能被修改Process(pair.Value);
    }
    
  4. 值类型注意事项

    // 值类型更新需特殊处理
    var dict = new ConcurrentDictionary<string, (int, DateTime)>();dict.AddOrUpdate("task", k => (0, DateTime.UtcNow),(k, v) => (v.Item1 + 1, DateTime.UtcNow)
    );
    

性能考量

  1. 读取密集型场景:性能接近无锁读取
  2. 写入密集型场景:比锁+Dictionary 性能高 2-3 倍
  3. 混合工作负载:在高并发下表现最佳

使用场景

  1. 缓存系统
  2. 实时监控/统计
  3. 并行计算中间结果
  4. 高并发计数器
  5. 任务调度系统(如所述进度监控)

总结

ConcurrentDictionary 是 .NET 中处理并发字典操作的首选方案,它:

  • 提供线程安全的原子操作
  • 比手动锁实现更高效
  • 简化多线程编程模型
  • 特别适合高频读写的场景

在任务进度监控系统中,使用 ConcurrentDictionary 可以安全高效地管理多个任务的进度状态,确保在高并发环境下数据的一致性和实时性。

http://www.dtcms.com/a/321485.html

相关文章:

  • 并发编程(五)ThreadLocal
  • 生产环境Tomcat运行一段时间后,如何测试其性能是否满足后续使用
  • Rust语言序列化和反序列化vec<u8>,serde库Serialize, Deserialize,bincode库(2025年最新解决方案详细使用)
  • AI 智能体框架:LlamaIndex
  • 国内如何使用体验到GPT-5呢?附GPT快速升级Plus计划保姆级教程
  • 大模型量化上溢及下溢解析
  • 达梦DMFLDR导出和导入的方法
  • 以任务为中心的智能推荐系统架构设计:原理、实现与挑战分析
  • 深入理解Java集合框架:核心接口、实现类与实战选择
  • Vue2中,Promise.all()调用多个接口的用法
  • Numpy科学计算与数据分析:Numpy文件操作入门之数组数据的读取和保存
  • 智慧社区(十)——声明式日志记录与小区地图功能实现
  • 解决MinIO上传图片后返回URL无法访问的问题
  • Linux 启动流程实战:Device Tree 全解析与驱动绑定机制
  • 【LLM实战】RAG高级
  • 从0到1开发剧本杀小程序:全流程指南与避坑指南
  • 使用 C# 通过 .NET 框架开发应用程序的安装与环境配置
  • 网吧在线选座系统|基于java和小程序的网吧在线选座小程序系统设计与实现(源码+数据库+文档)
  • [202403-E]春日
  • 小程序难调的组件
  • 悬赏任务系统网站兼职赚钱小程序搭建地推抖音视频任务拉新源码功能详解二开
  • LangChain学习笔记05——多模态开发与工具使用
  • react+echarts实现变化趋势缩略图
  • LabVIEW数字抽取滤波
  • 点播服务器
  • RabbitMQ 中无法路由的消息会去到哪里?
  • Spring AMQP 入门与实践:整合 RabbitMQ 构建可靠消息系统
  • Android12 Framework Sim卡pin与puk码解锁
  • 用LaTeX优化FPGA开发:结合符号计算与Vivado工具链(二)
  • Nature论文-预测和捕捉人类认知的基础模型-用大模型模拟人类认知