你不了解的Dictionary和ConcurrentDictionary
最近在做项目时,多线程中使用Dictionary
的全局变量时,发现数据并没有存入到Dictionary
中,但是程序也没有报错,经过自己的一番排查,发现Dictionary为非线程安全类型,因此我感觉数据没有写进去的原因是多线程在争夺全局变量时,导致数据未写入,于是去对Dictionary
进行仔细的了解。
经过在网上查阅资料,发现大家讲解最多的是Dictionary
(非线程安全)和ConcurrentDictionary
(线程安全),于是我也从这两个关键字来仔细的讲解,顺便也更加深入的认识它们。
Dictionary
怎样解决线程安全问题?可以使用加锁、线程全局变量、使用ConcurrentDictionary
等。下面我们就一起来看看吧,Let’s go。
Dictionary
Dictionary<TKey, TValue>
泛型类提供了键值对映射,通过TKey
来检索值的速度非常快,时间复杂度接近与O(1),是因为Dictionary
通过哈希表实现,是一种变相的HashTable
,采用分离链接散列表的数据结构解决哈希冲突问题。
在早期的C#版本中,可以将集合初始值设定项用于序列样式集合,包括在键值对周围添加括号而得到Dictionary<TKey, TValue>
,如:
Dictionary<int, string> msgs = new Dictionary<int, string>()
{{ 1, "Hello, "},{ 2 , "World"},{ 3, "!"}
};
而新的语法支持使用索引分配到集合中,如:
Dictionary<int, string> MsgErrs = new Dictionary<int, string>()
{[1] = "Hello, ",[2] = "World",[3] = "!",
};
上述两者在初始化赋值时都差不多,但是两者还是有一些区别,前者在初始化时出现重复key
值,程序会直接报错。而后者初始化时,key
可以有重复值,系统会自动过滤掉重复的key
值,程序也不会报错。
实现键/值对集合
每次对字典的添加都包含一个值与其关联的值,通过使用键来检索十分方便;
如果使用集合初始值设定项生成Dictionary
集合,可以使用如下方法:
public static Dictionary<string, Element> BuildDic(){return new Dictionary<string, Element>{{"L", new Element(){Symbol = "L", Name = "Postass", AutominNumber = 9}},{"Q", new Element(){ Symbol = "Q", Name = "Calcium", AutominNumber = 99}},{"M", new Element(){ Symbol = "JY", Name = "JYaoiang", AutominNumber=7924}}};}
Dictionary添加值
public static void IterateDictionary(){Dictionary<string, Element> element = BuildDic();foreach(KeyValuePair<string, Element> keyValue in element){Element ele = keyValue.Value;Console.WriteLine(string.Format("Key={0}; Values={0};{1};{2}", keyValue.Key, ele.Symbol, ele.Name, ele.AutominNumber));}}public static Dictionary<string, Element> BuildDictionary(){var elements = new Dictionary<string, Element>();AddDictionary(elements, "L", "LLL", 9);AddDictionary(elements, "J", "LJLHHH", 19);AddDictionary(elements, "A", "ABABABA", 20);return elements;}public static void AddDictionary(Dictionary<string, Element> elements, string symbol, string name, int num){Element ele = new Element(){Symbol = symbol,Name = name,AutominNumber = num};elements.Add(key: symbol, value: ele);}
ContainsKey方法和Item[]属性
public static void FindDictionary(string symbol){Dictionary<string, Element> elements = BuildDictionary();if (elements.ContainsKey(symbol)){Element ele = elements[symbol];Console.WriteLine("Found: " + ele.Name);}else{Console.WriteLine("Not found " + symbol);}}
TryGetValue方法
public static void FindDictionaryOfTryGetValue(string symbol){Dictionary<string, Element> elements = BuildDictionary();Element ele = null;if(elements.TryGetValue(symbol, out ele)){Console.WriteLine("Found: " + ele.Name);}else{Console.WriteLine("Not found " + symbol);}}
在这里讲解了Dictionary的常见使用方法,这里在啰嗦一句,不知道大家在使用Dictionary时有没有注意带Add方法和TryAdd方法,这两个方法到底有什么区别?
我们都知道,在往Dictionary中添加键值时,键是不能重复的,如果使用Add方法添加重复的key,会使程序报错。要想避免这个问题,则可以使用TryAdd方法,当添加重复键值使,该方法会返回false,就可以避免此类问题。
ConcurrentDictionary
在.NET Framework 4
以及更新的版本中,System.Collections.Concurrent
命名空间中的集合可提供高效的线程安全操作,以便从多个线程访问集合项。
当有多个线程访问集合项时,应该使用System.Collections.Concurrent
命名空间中的类,而不是使用System.Collections.Generic
和System.Collections命名空间中的类。
System.Collections.Concurrent
命名空间中的类:BlockingCollection、ConcurrentDictionary<TKey, TValue>、ConcurrentQueue<T>、ConcurrentStack<T>
。
System.Collections
命名空间中的类不会将元素作为特别类型化的对象存储,而是作为object
类型的对象存储。
ConcurrentDictionary
用法与Dictionary
类似,这里就不再详细讲解了。但是ConcurrentDictionary
只能使用TryAdd
方法,而Dictionary
可以使用Add
和TryAdd
方法。
Dictionary和ConcurrentDictionary多线程
带大家认识完Dictionary
和ConcurrentDictionary
,下面就回归主题,看看两者在多线程方面的使用情况。
代码如下:
ConcurrentDictionary<int, string> keys = new ConcurrentDictionary<int, string>();
keys.TryAdd(1, "LL");
keys.TryAdd(2, "LL");
Dictionary<int, string> dic = new Dictionary<int, string>();
dic.Add(1, "OJ");
dic.TryAdd(2, "R");
Stopwatch stopwatch = new Stopwatch();
#region 写入
stopwatch.Start();
Parallel.For(0, 10000000, i =>
{lock (dic){dic[i] = new Random().Next(100, 99999).ToString();}
});
stopwatch.Stop();
Console.WriteLine("Dictionary加锁写入花费时间:{0}", stopwatch.Elapsed);
stopwatch.Restart();
Parallel.For(0, 10000000, i =>
{keys[i] = new Random().Next(100, 99999).ToString();
});
stopwatch.Stop();
Console.WriteLine("ConcurrentDictionary加锁写入花费时间:{0}", stopwatch.Elapsed);
#endregion
#region 读取
string result = string.Empty;
stopwatch.Restart();
Parallel.For(0, 10000000, i =>
{lock (dic){result = dic[i];}
});
stopwatch.Stop();
Console.WriteLine("Dictionary加锁读取花费时间:{0}", stopwatch.Elapsed);
stopwatch.Restart();
Parallel.For(0, 10000000, i =>
{result = keys[i];
});
stopwatch.Stop();
Console.WriteLine("ConcurrentDictionary加锁读取花费时间:{0}", stopwatch.Elapsed);
#endregion
Console.ReadLine();
可以发现,在多线程下,加了lock
的Dictionary
写入性能要比ConconcurrentDictionary
的写入性能更好,读取数据ConcurrentDictionary性能更好。
当我们将写入的数据增加到20000000时,ConcurrentDictionary
写入性能明显就比Dictionary
性能差了,但是读取性能ConcurrentDictionary
更好。
当我们将写入的数据增加到2000000时,ConcurrentDictionary
写入性能还是比Dictionary
性能差,但是读取性能ConcurrentDictionary
更好。
综上,经过对两者的比较,ConcurrentDictionary
读取性能更好,Dictionary
写入性能更好。
至于,具体是什么原因,到时候我会进行深入讲解,这篇文章大致就讲到这里了,我们下篇文章见。
相关文章:

你不了解的Dictionary和ConcurrentDictionary
最近在做项目时,多线程中使用Dictionary的全局变量时,发现数据并没有存入到Dictionary中,但是程序也没有报错,经过自己的一番排查,发现Dictionary为非线程安全类型,因此我感觉数据没有写进去的原因是多线程…...
c++类模板,嵌套类模板,模板链表,动态数组
c类模板,嵌套类模板,模板链表,动态数组 一.类模板 1.类模板的书写 代码如下 template<typename T>//模板 class CTest {//类 public:T m_a;CTest(const T&a):m_a(a){}void fun1() {cout << typeid(m_a).name() << …...

【Flutter】【基础】CustomPaint 绘画功能,绘制各种图形(二)
CustomPaint 使用实例和代码: 1.canvas.drawColor 绘制背景颜色 class MyPainter1 extends CustomPainter {overridevoid paint(Canvas canvas, Size size) {//绘制背景颜色,整个UI 现在就是红色的canvas.drawColor(Colors.red, BlendMode.srcATop);}…...

YOLOv5修改注意力机制CBAM
直接上干货 CBAM注意力机制是由通道注意力机制(channel)和空间注意力机制(spatial)组成。 传统基于卷积神经网络的注意力机制更多的是关注对通道域的分析,局限于考虑特征图通道之间的作用关系。CBAM从 channel 和 sp…...

计算机网络 网络层 概述
...
算法练习--动态规划 相关
文章目录 走方格的方案 走方格的方案 请计算n*m的棋盘格子(n为横向的格子数,m为竖向的格子数)从棋盘左上角出发沿着边缘线从左上角走到右下角,总共有多少种走法,要求不能走回头路,即:只能往右和…...
JAVA volatile 关键字
volatile 是JAVA虚拟机提供的轻量级的同步机制,有三大特性 1、保证可见性 2、不保证原子性 3、禁止指令重排 JMM JAVA内存模型本身是一种抽象的概念并不真实存在 它描述的是一组规则或规范,提供这组规范定义了程序中各个变量(包括实例变…...

[Leetcode] [Tutorial] 回溯
文章目录 46. 全排列Solution 78. 子集Solution 17. 电话号码的字母组合Solution 39. 组合总和Solution 22. 括号生成Solution 46. 全排列 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例: 输入&…...

STM32 CubeMX USB_MSC(存储设备U盘)
STM32 CubeMX STM32 CubeMX USB_MSC(存储设备U盘) STM32 CubeMX前言 《使用内部Flash》——U盘一、STM32 CubeMX 设置USB时钟设置USB使能UBS功能选择FATFS功能 二、代码部分修改代码"usbd_storage_if.c"修改代码"user_diskio.c"main函数初始化插…...

湘大 XTU OJ 1214 A+B IV 题解:数位移动的本质+布尔变量标记+朴素模拟
一、链接 AB IV 二、题目 题目描述 小明喜欢做ab的算术,但是他经常忘记把末位对齐,再进行加,所以,经常会算错。 比如1213,他把12左移了1位,结果变成了133。 小明已经算了一些等式,请计算一下…...

以商业大数据技术助力数据合规流通体系建立,合合信息参编《数据经纪从业人员评价规范》团标
经国务院批准,由北京市人民政府、国家发展和改革委员会、工业和信息化部、商务部、国家互联网信息办公室、中国科学技术协会共同主办的2023 全球数字经济大会于近期隆重召开。由数交数据经纪(深圳)有限公司为主要发起单位,合合信息…...

【论文阅读】Deep Instance Segmentation With Automotive Radar Detection Points
基于汽车雷达检测点的深度实例分割 一个区别: automotive radar 汽车雷达 : 分辨率低,点云稀疏,语义上模糊,不适合直接使用用于密集LiDAR点开发的方法 ; 返回的物体图像不如LIDAR精确,可以…...

易服客工作室:如何创建有用的内容日历
利用技巧和工具优化您的内容营销效率和效果。创建一个内容日历,您的整个团队都会从中受益! 欢迎来到熙熙攘攘、瞬息万变的内容营销世界,在这里,截止日期到来的速度比喝咖啡的猎豹还要快。 现在,想象一下在没有地图、…...

Excel革命,基于电子表格开发的新工具,不是Access和Power Fx
深谙其道 在日常工作中,Excel是许多人不可或缺的办公工具。 是微软的旗下产品,属于Microsoft 365套件中的一部分,强大的数据处理和计算功能,被普遍应用在全球各行各业的人群当中,是一款强大且普及的电子表格软件。 于…...

“崩溃”漏洞会影响英特尔 CPU 的使用寿命,可能会泄露加密密钥等
对于 CPU 安全漏洞来说,本周是重要的一周。昨天,不同的安全研究人员发布了两个不同漏洞的详细信息,一个影响多代英特尔处理器,另一个影响最新的 AMD CPU。“ Downfall ”和“ Inception ”(分别)是不同的错…...

17.电话号码的字母组合(回溯)
目录 一、题目 二、代码 一、题目 17. 电话号码的字母组合 - 力扣(LeetCode) 二、代码 class Solution {const char*data[10]{"","","abc","def","ghi","jkl","mno","pq…...
Redis小例子
MAC电脑下Redis的安装: brew install redis下面给一个Java操作redis的小例子 import redis.clients.jedis.Jedis;public class Demo {public static void main(String[] args) {// 创建 Jedis 客户端实例,连接到本地 Redis 服务器,默认端口…...

ETLCloud+MaxCompute实现云数据仓库的高效实时同步
MaxCompute介绍 MaxCompute是适用于数据分析场景的企业级SaaS(Software as a Service)模式云数据仓库,以Serverless架构提供快速、全托管的在线数据仓库服务,消除了传统数据平台在资源扩展性和弹性方面的限制,最小化用…...

HTTP代理授权方式介绍
在网络爬虫过程中,我们经常需要使用HTTP代理来实现IP隐藏、突破限制或提高抓取效率。而为了确保代理的正常使用,并避免被滥用,代理服务商通常会采用授权方式。在本文中,我们将介绍几种常见的HTTP代理授权方式,以帮助你…...

《合成孔径雷达成像算法与实现》Figure3.4
代码对补零信号与未补零信号都进行了实现,补零信号更加贴近书中图3.4的样子: clc clear all close all%参数设置 TBP 100; %时间带宽积 T 10e-6; %脉冲持续时间 alpha_os [1.4,1.2,1.0,0…...

eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】
微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来,Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

边缘计算医疗风险自查APP开发方案
核心目标:在便携设备(智能手表/家用检测仪)部署轻量化疾病预测模型,实现低延迟、隐私安全的实时健康风险评估。 一、技术架构设计 #mermaid-svg-iuNaeeLK2YoFKfao {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg…...
AtCoder 第409场初级竞赛 A~E题解
A Conflict 【题目链接】 原题链接:A - Conflict 【考点】 枚举 【题目大意】 找到是否有两人都想要的物品。 【解析】 遍历两端字符串,只有在同时为 o 时输出 Yes 并结束程序,否则输出 No。 【难度】 GESP三级 【代码参考】 #i…...

页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
拉力测试cuda pytorch 把 4070显卡拉满
import torch import timedef stress_test_gpu(matrix_size16384, duration300):"""对GPU进行压力测试,通过持续的矩阵乘法来最大化GPU利用率参数:matrix_size: 矩阵维度大小,增大可提高计算复杂度duration: 测试持续时间(秒&…...

均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态
前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...