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入门教程之十一迭代器、生成器和装饰器
迭代器 迭代是Python最强大的功能之一,是访问集合元素的一种方式. 迭代器是一个可以记住遍历的位置的对象. 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退 ...
- ARouter源码分析
源码看过好几遍了,但是总是会忘记,特此记录下 先从注解处理器开始 BaseProcessor是其他三个注解处理器的抽象类,子类去实现process方法.在其中的init方法中会获取我们的module模 ...
- 【D01】Django中实现带进度条的倒计时功能(简易版)
首先说明简易版是只有一个 倒计时 和一个 进度条,页面加载后自动开始计时,下次计时需要手动刷新页面. 后续会更新实现完整的倒计时功能的文章 前期准备 前端框架 你需要准备一些前端框架:Bootstra ...
- nginx 极简教程
什么是 Nginx? Nginx (engine x) 是一款轻量级的 Web 服务器 .反向代理服务器及电子邮件(IMAP/POP3)代理服务器. 什么是反向代理? 反向代理(Reverse Pro ...
- Docker Compose 部署GitLab
先决条件 Docker Engine和Docker Compose是必需的.请参阅在CentOS上安装Docker Engine. 建议使用4核的服务器,同时至少分配4G的内存,理论上4核4G可最多支 ...
- 第一章:PyTorch 入门
第一章:PyTorch 入门 1.1 Pytorch 简介 1.1.1 PyTorch的由来 1.1.2 Torch是什么? 1.1.3 重新介绍 PyTorch 1.1.4 对比PyTorch和Te ...
- Selenium 打包为.exe执行
前言:不依赖环境执行,拓展UI自动化使用的场景 一.项目结构介绍 case:测试用例次存放目录 config:主要存放yaml文件配置 ele:元素的定位以及执行动作 tools:HTMLTestRu ...
- DP做题记录
P1140 相似基因 考虑如何设计状态. 设给出的两个串为串 \(A\) 和串 \(B\),长度分别为 \(n\) 和 \(m\). 我们用 \(f[i][j]\) 来表示前 \(i\) 个 \(A\ ...
- Python_16 配置文件与封装
一.查缺补漏 1. ctrl + alt +L 规范格式 2. Python 使用 ini&yaml 配置文件 http://testingpai.com/article/1621245437 ...
- 百度飞桨(PaddlePaddle)-数字识别
手写数字识别任务 用于对 0 ~ 9 的十类数字进行分类,即输入手写数字的图片,可识别出这个图片中的数字. 使用 pip 工具安装 matplotlib 和 numpy python -m pip i ...