C# - ConcurrentDictionary 并发场景使用注意事项
1 自身作为 Enumerable 的遍历
自身作为可遍历对象,键值对为元素进行遍历,是线程安全的,但不提供快照,遍历过程中集合产生变更会直接反馈至此次遍历过程中。但并不一定能够保障获取数据的过程中,映射出所有遍历过程中发生的变更,比如,已经遍历过的元素发生了变更或删除,便按已经遍历过的处理了,不会再次处置。
1.1 一起了解源码
1.2 几点概念
- 线程安全:支持并发读写集合,能够保证集合的数据完整性和最终一致性。
- 快照(snapshot):集合快照时的数据内容和状态,原集合发生任何变更都不会体现在快照当中。如发生在遍历等操作前,则操作前集合中是哪些字段就是哪些,后续发生变更也不会反馈到此次操作当中。
- 集合变更:对于集合的增(添加元素)、删(移除元素)、改(变更元素属性)
2 做了 LINQ 操作之后进行遍历
由于没有做快照且没有自身 GetEnumerator 的线程安全处理,对集合做了 Where、OrderBy 等操作后,其对象变为 IEnumerable,此时遍历若集合内元素发生变更,则会报错。
2.1 解决办法
- 使用 ToArray() 或 Values 获取快照
- 再执行对应的 LINQ 操作。则操作针对的是快照,不会因集合发生变更而影响快照内容,从而产生线程安全问题
3 this[index]
- getter:TryGetValue
- setter:TryAddInternal:updateIfExists 为 true
4 TryAdd()
TryAddInternal:updateIfExists 为 false
5 TryUpdate()
- 找得到键,尝试用新值更新旧值。
- 找不到返回 false。
6 私有方法 TryAddInternal()
- 找得到键,返回 false。同时若 updateIfExists 为 true 则用要添加的值更新原值。
- 找不到则尝试添加并返回 true。
6.1 一起了解源码
7 AddOrUpdate()
- TryGetValue,若键存在,TryUpdate。
- 若键不存在,TryAddInternal。
- 如果 try update 或 try add 没有成功返回 false,会反复尝试重新 get 再根据 get 的结果再次 try update 或 try add。
7.1 其所解决的多线程并发问题
- A、B 两个线程同时想向集合添加键相同,值不相同的元素。集合中没有该键。
- A、B 两者都没 get 到 key
- A 先进 add,添加成功,key 对应 A 的值。
- B 后进 add,try add 失败,重新尝试
- 重新尝试 B 的处理,B get 到 key,updateValueFactory 通过将 value 作为引用对象,将 B 所需更新到 value 中的内容,在原有 value 的基础上添加到 value 中,而不影响原有 value(不同于 this[index] 的强制赋值)。
- try update,key 更新 value,同时包含 A 和 B 的内容。
AddOrUpdate 通过重新尝试可以解决并发问题,属于线程安全中不仅保障数据最终一致性,还能够保障数据不丢失的并发处理。
7.2 一起了解源码
8 Values
通过加锁达到快照效果,遍历 Values 的话所遍历的是修改前的集合,遍历过程中集合发生的变更不会体现在此次遍历当中。由于是快照,无论直接遍历还是 Linq 操作后遍历都是线程安全的。
8.1 一起了解源码
9 ToArray()
通过加锁达到快照效果,遍历 ToArray 后的 KeyValuePair 数组的话所遍历的是修改前的集合,遍历过程中集合发生的变更不会体现在此次遍历当中。由于是快照,无论直接遍历还是 Linq 操作后遍历都是线程安全的。
9.1 一起了解源码
C# - ConcurrentDictionary 并发场景使用注意事项的更多相关文章
- ConcurrentDictionary并发字典知多少?
背景 在上一篇文章你真的了解字典吗?一文中我介绍了Hash Function和字典的工作的基本原理. 有网友在文章底部评论,说我的Remove和Add方法没有考虑线程安全问题. https://doc ...
- 【性能诊断】六、并发场景的性能分析(windbg案例,大量的内部异常造成CPU飙升)
在做产品的某个核心模块的性能优化时,发现压到100并发时应用服务器的CPU就飙升至90%以上,50并发以后TPS就基本定格在一个数值上.使用性能监视器收集应用服务器的数据,发现每秒的.NET CLR ...
- 高并发场景之RabbitMQ篇
上次我们介绍了在单机.集群下高并发场景可以选择的一些方案,传送门:高并发场景之一般解决方案 但是也发现了一些问题,比如集群下使用ConcurrentQueue或加锁都不能解决问题,后来采用Redis队 ...
- Qunar机票技术部就有一个全年很关键的一个指标:搜索缓存命中率,当时已经做到了>99.7%。再往后,每提高0.1%,优化难度成指数级增长了。哪怕是千分之一,也直接影响用户体验,影响每天上万张机票的销售额。 在高并发场景下,提供了保证线程安全的对象、方法。比如经典的ConcurrentHashMap,它比起HashMap,有更小粒度的锁,并发读写性能更好。线程安全的StringBuilder取代S
Qunar机票技术部就有一个全年很关键的一个指标:搜索缓存命中率,当时已经做到了>99.7%.再往后,每提高0.1%,优化难度成指数级增长了.哪怕是千分之一,也直接影响用户体验,影响每天上万张机 ...
- HashMap在并发场景下踩过的坑
本文来自网易云社区 作者:张伟 关于HashMap在并发场景下的问题有很多人,很多公司遇到过!也很多人总结过,我们很多时候都认为这样都坑距离自己很远,自己一定不会掉入这样都坑.可是我们随时都有就遇到了 ...
- 【转】记录PHP、MySQL在高并发场景下产生的一次事故
看了一篇网友日志,感觉工作中值得借鉴,原文如下: 事故描述 在一次项目中,上线了一新功能之后,陆陆续续的有客服向我们反应,有用户的个别道具数量高达42亿,但是当时一直没有到证据表示这是,确实存在,并且 ...
- 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存
原文:http://blog.csdn.net/heyewu4107/article/details/71009712 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存 问 ...
- 高并发场景下System.currentTimeMillis()的性能问题的优化 以及SnowFlakeIdWorker高性能ID生成器
package xxx; import java.sql.Timestamp; import java.util.concurrent.*; import java.util.concurrent.a ...
- 高并发场景之RabbitMQ
高并发场景之RabbitMQ 上次我们介绍了在单机.集群下高并发场景可以选择的一些方案,传送门:高并发场景之一般解决方案 但是也发现了一些问题,比如集群下使用ConcurrentQueue或加锁都不能 ...
- HttpClient在高并发场景下的优化实战
在项目中使用HttpClient可能是很普遍,尤其在当下微服务大火形势下,如果服务之间是http调用就少不了跟http客户端找交道.由于项目用户规模不同以及应用场景不同,很多时候可能不需要特别处理也. ...
随机推荐
- Python之八大数据类型
数据类型之整型int 与浮点型 float 整型也就是int型 其实就是整数 如: print(type(10)) 浮点型就是float 其实就是小数 如: print(type(10.0)) # 这 ...
- 【Diary】JZSC 2020 旅 游 记(迫真
Day-2 期末考试的day1. 科目是数学 政治 语文.数学25.(3)没动.政治各种抄选择题选项()语文难得写完了.作文压根不知道写的什么 Day-1 期末考试的day2. 科目是英语 物理 历史 ...
- Java构建树结构的公共方法
一.前提 pId需要传入用来确认第一级的父节点,而且pId可以为null. 树实体类必须实现:TreeNode接口 MyTreeVo必须有这三个属性:id.pId.children 可以根据不同需求, ...
- Nvidia Tensor Core初探
1 背景 在基于深度学习卷积网络的图像处理领域,作为计算密集型的卷积算子一直都是工程优化的重点,而卷积计算一般转化为矩阵乘运算,所以优化矩阵乘运算自然成为深度学习框架最为关心的优化方向之一.鉴于此,N ...
- JUC(三)集合的线程安全
目录 集合的线程安全 list集合线程不安全演示 Vector解决 Collections.synchronizedList JUC 解决方案:CopyOnWriteArrayList HashSet ...
- 【Vue】前端解决跨域问题
Vue解决跨域问题 什么是跨域:违背了同源策略,即协议名.主机名.端口号必须一致.浏览器与服务器之间存在跨域问题,而服务器与服务器之间由于通过Http通信是不存在跨域问题的. 如图所示,浏览器 ...
- RDIFramework.NET Web版报表管理-助力企业高效智能图表
功能描述 在RDIFramework.NET Web版本中全新的报表管理功能模块,非常实用的功能,重量级推荐.主要用于对日常常用的报表做定制展示.可以自动发布到模块(就可授权给指定资源访问),在报表定 ...
- Dotnet初探: 尝试使用 dotnet6 的miniapi
引子 最近我们学校要求我们使用dotnet实现一个登录功能,由于我们学校的教程老旧(万年经典asp .net 4.x,慢的要死),我看有高性能又免费的Dotnet6不用,还又要退回几年前,于是决定另开 ...
- MAPPO学习笔记(2) —— 从MAPPO论文入手
在有了上一节一些有关PPO算法的概念作为基础后,我们就可以正式开始对于MAPPO这一算法的学习. 那么,既然要学习一个算法,就不得不去阅读提出这一算法的论文.那么本篇博客将从MAPPO的论文出发,对M ...
- json解析异常显示{“$ref“:“$[0]“}
在编写测试代码实现一个组织架构树的功能时,部门的parent部门没有显示,出现了json解析异常错误[{"r e f " : " ref":"ref& ...