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 _);// 在多线程环境中操作 ConcurrentDictionaryParallel.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); // 输出:2var dict = new ConcurrentDictionary<int, string>();
//IsEmpty 属性
Console.WriteLine(dict.IsEmpty); // 输出:True
dict.TryAdd(1, "one");
Console.WriteLine(dict.IsEmpty); // 输出:Falsevar 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); // 输出:Falsevar 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); // 输出:Falsevar 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); // 输出:Truevar 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等,能够灵活地处理并发操作,同时避免了传统字典在多线程场景下的线程安全问题。
相关文章:
C#开发——ConcurrentDictionary集合
ConcurrentDictionary<TKey, TValue> 是 C# 中一个专为多线程场景设计的线程安全字典集合,位于 System.Collections.Concurrent 命名空间中。它允许多个线程同时对字典进行读写操作,而无需额外的同步措施。 一、集合特征 此集合有如下特征…...
深入浅出ES6:现代JavaScript的基石
ES6(ECMAScript 2015)是JavaScript语言的一次重大更新,引入了许多新特性,使JavaScript更加强大、优雅和易于维护。这些特性已经成为现代JavaScript开发的基石,掌握它们对于任何JavaScript开发者都至关重要。本文将深入…...
小型字符级语言模型的改进方向和策略
小型字符级语言模型的改进方向和策略 一、回顾小型字符级语言模型的处理流程 前文我们已经从零开始构建了一个小型字符级语言模型,那么如何改进和完善我们的模型呢?有哪些改进的方向?我们先回顾一下模型的流程: 图1 小型字符级语言模型的处理流程 (1)核心模块交互过程:…...
一周学会Flask3 Python Web开发-Jinja2模板访问对象
锋哥原创的Flask3 Python Web开发 Flask3视频教程: 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 如果渲染模板传的是对象,如果如何来访问呢? 我们看下下面示例: 定义一个Student类 cla…...
vue 3D 翻页效果
<template><view class"swipe-container" touchstart"onTouchStart" touchmove"onTouchMove" touchend"onTouchEnd"><view class"page">初始页</view></view> </template><script&g…...
JSONL 是什么格式
JSONL(JSON Lines)格式是一种简洁的文件格式,它将每一行作为一个独立的JSON对象,每个对象之间通过换行符分隔。JSONL常用于处理大规模数据,特别是在日志文件、机器学习数据集或数据流应用中。 示例 假设我们有以下3条…...
npm : 无法加载文件 E:\ProgramFiles\Nodejs\npm.ps1,因为在此系统上禁止运行脚本。
这个错误是因为 Windows 系统的 PowerShell 执行策略 限制了脚本的运行。默认情况下,PowerShell 的执行策略是 Restricted,即禁止运行任何脚本。以下是解决该问题的步骤: 1. 检查当前执行策略 打开 PowerShell(管理员权限&#x…...
pycharm 调试 debug 进入 remote_sources
解决办法1: pycharm函数跳转到remote_sources中的文件中_pycharm修改remotesource包存放地址-CSDN博客 file->settings->project structure将项目文件夹设为"Sources"(此时文件夹会变为蓝色)。 解决方法2 Debug:使用Pychar…...
测试面试题:以一个登录窗口为例,设计一下登录界面测试的思路和方法
在测试登录窗口时,可以从 表单测试、 逻辑判断和 业务流程三个方面设计测试思路和方法。以下是一个详细的测试方案: 1. 表单测试 表单测试主要关注输入框、按钮等UI元素的正确性和用户体验。 测试点: 输入框测试 用户名和密码输入框是否正常显示。输入框是否支持预期的字符类…...
[特殊字符] 蓝桥杯 Java B 组 之最小生成树(Prim、Kruskal) 并查集应用
Day 3:最小生成树(Prim、Kruskal) & 并查集应用 📖 一、最小生成树(MST)简介 最小生成树(Minimum Spanning Tree, MST) 是一个 无向连通图 的 最小代价子图,它包含 …...
【蓝桥杯】1.k倍区间
前缀和 #include <iostream> using namespace std; const int N100010; long long a[N]; int cnt[N]; int main(){int n, m;cnt[0] 1;cin >> n >> m;long long res 0;for(int i 1; i < n; i){scanf("%d", &a[i]);a[i] a[i-1];res cnt…...
机器人部分专业课
华东理工 人工智能与机器人导论 Introduction of Artificial Intelligence and Robots 必修 考查 0.5 8 8 0 1 16477012 程序设计基础 The Fundamentals of Programming 必修 考试 3 64 32 32 1 47450012 算法与数据结构 Algorithm and Data Structure 必修 考试 3 56 40 …...
SpringBoot两种方式接入DeepSeek
方式一:基于HttpClient 步骤 1:准备工作 获取 DeepSeek API 密钥:访问 DeepSeek 的开发者平台,注册并获取 API 密钥。 步骤 2:引入依赖 <dependency><groupId>org.springframework.boot</groupId&g…...
Maven——Maven开发经验总结(1)
摘要 本文总结了 Maven 开发中的多个关键经验,包括如何根据版本号决定推送到 releases 或 snapshots 仓库,如何在构建过程中跳过测试,父项目如何控制子项目依赖版本,父项目依赖是否能传递到子项目,如何跳过 Maven dep…...
DeepSeek掘金——调用DeepSeek API接口 实现智能数据挖掘与分析
调用DeepSeek API接口:实现智能数据挖掘与分析 在当今数据驱动的时代,企业和开发者越来越依赖高效的数据挖掘与分析工具来获取有价值的洞察。DeepSeek作为一款先进的智能数据挖掘平台,提供了强大的API接口,帮助用户轻松集成其功能到自己的应用中。本文将详细介绍如何调用D…...
gitlab 解决双重认证无法登录remote: HTTP Basic: Access denied.
问题:gitlab开启了双因素认证导致无法正常使用 如进行了 OAuth configuration 在进行git操作时如下提示 remote: HTTP Basic: Access denied. The provided password or token is incorrect or your account has 2FA enabled and you must use a personal access…...
【Microsoft PowerPoint for Mac】2分钟配置-MAC一键删除PPT中的所有备注
MAC一键删除PPT中的所有备注 1.搜索自动操作2.点击快速操作3.搜索并运行AppleScript4.输入代码,并选择只应用于Microsoft PowerPoint for Mac【右上角】5. CRTLS保存为“清除当前文稿中的所有备注”,PPT中应用。 MAC没自带,需要自己配置 1.搜…...
人工智能 阿里云算力服务器的使用
获取免费的阿里云服务器 阿里云免费使用地址: https://free.aliyun.com/ 选择 人工智能平台 PAI 选择交互式建模 再选建立实例。 选择对应的GPU 和镜像,点击确认。 注意:250个小时,用的时候开启,不用的时候关闭&…...
硬核技术组合!用 DeepSeek R1、Ollama、Docker、RAGFlow 打造专属本地知识库
文章目录 一、引言二、安装Ollama部署DeepSeekR1三、安装Docker四、安装使用RAGFlow4.1 系统架构4.2 部署流程4.3 使用RAGFlow4.4 在RAGFlow中新增模型4.5 创建知识库4.6 创建私人助理使用RGA 一、引言 本地部署DeepSeek R1 Ollama RAGFlow构建个人知识库,通过将…...
记录此刻:历时两月,初步实现基于FPGA的NVMe SSD固态硬盘存储控制器设计!
背景 为满足实验室横向项目需求,在2024年12月中下旬导师提出基于FPGA的NVMe SSD控制器研发项目。项目核心目标为:通过PCIe 3.0 x4接口实现单盘3000MB/s的持续读取速率。 实现过程 调研 花了半个月的时间查阅了一些使用FPGA实现NVME SSD控制器的论文、…...
pytorch入门级项目--基于卷积神经网络的数字识别
文章目录 前言1.数据集的介绍2.数据集的准备3.数据集的加载4.自定义网络模型4.1卷积操作4.2池化操作4.3模型搭建 5.模型训练5.1选择损失函数和优化器5.2训练 6.模型的保存7.模型的验证结语 前言 本篇博客主要针对pytorch入门级的教程,实现了一个基于卷积神经网络&a…...
yolov12部署(保姆级教程)
yolov12部署 戳链接访问原论文论文地址 戳链接访问原代码代码地址 直接把源代码以ZIP的形式下载到本地,然后解压用IDE打开就可以了(这一步比较简单不过多介绍) 在IDE中打开可以看见一个README.md文件,这里有我们将yolov12部署本…...
对免认证服务提供apikey验证
一些服务不带认证,凡是可以访问到服务端口,都可以正常使用该服务,方便是方便,但是不够安全。 比如ollama默认安装后就是这样。现在据说网上扫一下端口11434,免apikey的ollama服务一大堆。。。 那我们怎样将本机安装的o…...
五、Three.js顶点UV坐标、纹理贴图
一部分来自1. 创建纹理贴图 | Three.js中文网 ,一部分是自己的总结。 一、创建纹理贴图 注意:把一张图片贴在模型上就是纹理贴图 1、纹理加载器TextureLoader 注意:将图片加载到加载器中 通过纹理贴图加载器TextureLoader的load()方法加…...
汽车零部件工厂如何通过ESD监控系统闸机提升产品质量
在汽车零部件工厂的生产过程中,静电带来的危害不容小觑。从精密的电子元件到复杂的机械部件,静电都可能成为影响产品质量的 “隐形杀手”。而 ESD 监控系统闸机的出现,为汽车零部件工厂解决静电问题、提升产品质量提供了关键的技术支持。 一、…...
Pi币与XBIT:在去中心化交易所的崛起中重塑加密市场
在加密货币市场迅猛发展的背景下,Pi币和XBIT正在成为投资者关注的焦点。Pi币作为一项创新的数字货币,通过独特的挖矿机制和广泛的用户基础,迅速聚集了大量追随者,展示了强大的市场潜力。同时,币应XBIT去中心化交易所的…...
【Python量化金融实战】-第2章:金融市场数据获取与处理:2.1 数据源概览:Tushare、AkShare、Baostock、通联数据(DataAPI)
本章将详细介绍四大主流金融数据源(Tushare、AkShare、Baostock、通联数据(DataAPI)),分析其特点与适用场景,并通过实战案例展示数据获取与处理的全流程。 👉 点击关注不迷路 👉 点击…...
详解golang的Gengine规则引擎
一:简介 Gengine是一款基于golang和AST(抽象语法树)开发的规则引擎, Gengine支持的语法是一种自定义的DSL, Gengine通过内置的解释器对规则文件进行解析,构建规则模型,进行相应的规则计算和数据处理。Gengine于2020年7月由哔哩哔哩(bilibili.com)授权开源。Gengine现已应用…...
首次使用WordPress建站的经验分享(一)
之前用过几种内容管理系统(CMS),如:dedeCMS、phpCMS、aspCMS,主要是为了前端独立建站,达到预期的效果,还是需要一定的代码基础的,至少要有HTML、Css、Jquery基础。 据说WordPress 是全球最流行的内容管理系统CMS,从现在开始记录一下使用WordPress 独立建站的步骤 选购…...
MySQL缓存命中率
什么是缓存命中率 MySQL 缓存命中率是衡量 MySQL 查询性能的一个重要指标,它表示缓存中的数据被查询请求成功返回的比例。较高的缓存命中率通常意味着较少的磁盘 I/O 操作,查询响应速度较快。MySQL 中有多个类型的缓存,如 查询缓存、InnoD…...
