dotnet 警惕 ConcurrentDictionary 使用 FirstOrDefault 获取到非预期的首项
在 dotnet 里面的 ConcurrentDictionary 是一个支持并发读写的线程安全字典,在这个字典里面有一些行为会出现随机性,即多次执行相同的代码返回的结果可能不相同。本文记录在 ConcurrentDictionary 使用 FirstOrDefault 获取到非预期的首项的问题
在 dotnet 里面,无论是对 List 列表,还是 Dictionary 字典等获取首项,使用 FirstOrDefault 总是可以获取到第一个加入到集合或字典里面的元素。然而这个行为在 ConcurrentDictionary 里面是不成立的。在 ConcurrentDictionary 里面如果使用 FirstOrDefault 方法,则随机获取到字典里面的一项,但对相同的一个 ConcurrentDictionary 对象多次调用 FirstOrDefault 方法,在不更改 ConcurrentDictionary 内容的情况下,可以稳定获取到相同的首项元素对象
简单来说就是在 ConcurrentDictionary 里面,调用 FirstOrDefault 方法,不能保证获取到的对象就是第一个加入到 ConcurrentDictionary 字典里面的对象
如以下代码例子
using System.Collections.Concurrent;
for (int i = 0; i < int.MaxValue; i++)
{
var dictionary = new ConcurrentDictionary<Foo, int>();
dictionary.TryAdd(new Foo(), i);
dictionary.TryAdd(new Foo(), i + 1);
var first = dictionary.FirstOrDefault();
if (first.Value != i)
{
// 证明首个不是第一个加入的
Console.WriteLine($"首个不是第一个加入的");
return;
}
}
class Foo
{
public Foo()
{
Number = _count;
_count++;
}
private static int _count;
public int Number { get; }
}
以上代码在一个大的循环里面,每次循环都创建一个字典,在给字典加入两个元素,最后加入的元素设置为和循环次数不相同的值,通过此可以用来在后续调用 FirstOrDefault 时判断获取到的元素是否首个加入字典的元素
运行代码可以看到,使用 FirstOrDefault 获取到的元素,不是第一个加入字典的元素。同时,多次运行代码,可以看到进入 if (first.Value != i) 不等于条件时的循环次数也会不相同,这就可以证明使用 FirstOrDefault 的执行结果比较随机
具体原理是在 ConcurrentDictionary 里面需要维护一个 Table 字典,字典里面存放的顺序和传入的 Key 对象的 Hash 有关,调用 FirstOrDefault 方法时获取到的是里面的 Table 字典的按照内存空间顺序的首项
由此原理即可知道,使用 FirstOrDefault 获取 ConcurrentDictionary 的首现是无法确保获取到的是首个加入字典的元素对象。同时如果在 ConcurrentDictionary 字典发生变更,比如不断加入值时,将导致调用 FirstOrDefault 无法稳定返回相同的对象
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 623c123b1d5e5669c5321c846d72c09e042135a6
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 623c123b1d5e5669c5321c846d72c09e042135a6
获取代码之后,进入 CerdearhachiRairwainalnearyal 文件夹
dotnet 警惕 ConcurrentDictionary 使用 FirstOrDefault 获取到非预期的首项的更多相关文章
- SQL-24 获取所有非manager员工当前的薪水情况,给出dept_no、emp_no以及salary ,当前表示to_date='9999-01-01'
题目描述 获取所有非manager员工当前的薪水情况,给出dept_no.emp_no以及salary ,当前表示to_date='9999-01-01'CREATE TABLE `dept_emp` ...
- SQL-10 获取所有非manager的员工emp_no
题目描述 获取所有非manager的员工emp_noCREATE TABLE `dept_manager` (`dept_no` char(4) NOT NULL,`emp_no` int(11) N ...
- [改善Java代码] 避免instanceof非预期结果
建议18: 避免instanceof非预期结果 instanceof是一个简单的二元操作符,它是用来判断一个对象是否是一个类实例的,其操作类似于>=.==,非常简单,我们来看段程序,代码如下: ...
- int.TryParse非预期执行引发的思考 ASP.NET -- WebForm -- 给图片添加水印标记 Windows -- 使用批处理文件.bat删除旧文件
int.TryParse非预期执行引发的思考 问题出现 这天在写一个页面,想谨慎些就用了int.TryParse,结果出问题了. 代码如下: Copy int id = 1000; //Reque ...
- 为什么委托的减法(- 或 -=)可能出现非预期的结果?(Delegate Subtraction Has Unpredictable Result)
当我们为一个委托写 -= 的时候,ReSharper 会提示“Delegate Subtraction Has Unpredictable Result”,即“委托的减法可能出现非预期的结果”.然而在 ...
- dotnet C# 给结构体字段赋值非线程安全
在 dotnet 运行时中,给引用对象进行赋值替换的时候,是线程安全的.给结构体对象赋值,如果此结构体是某个类的成员字段,那么此赋值不一定是线程安全的.是否线程安全,取决于结构体的大小,取决于此结构体 ...
- ReentrantLock获取到非公平锁的源码
/** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void l ...
- 警惕System.Environment.CurrentDirectory 获取当前目录
最近工作中,要做个客户端提醒的小工具:winform程序自然少不了要读取和应用程序同一个目录的配置文件(不是exe.config文件): 要读取当前应用程序所在目录我立马想到了System.Envir ...
- java最全的获取某个接口或者某个类所有对应的所有实现类和继承类的工具类--反射动态获取、非动态获取、按照路径获取等总结
我们直接上代码吧,代码中有注释说明. //直接看代码吧 import java.io.File; import java.lang.reflect.Field; import java.net.URL ...
- int.TryParse非预期执行引发的思考
问题出现 这天在写一个页面,想谨慎些就用了int.TryParse,结果出问题了. 代码如下: int id = 1000; //Request.QueryString["id"] ...
随机推荐
- 记录--Uni-app接入腾讯人脸核身
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 人脸核身功能有多种接入方式,其中包含微信H5.微信小程序.APP.独立H5.PC端.API接入6种方式. 我们的产品是使用uni-ap ...
- 记录--求你了,别再说不会JSONP了
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 JSONP是一种很远古用来解决跨域问题的技术,当然现在实际工作当中很少用到该技术了,但是很多同学在找工作面试过程中还是经常被问到,本文将带 ...
- Jmeter教程-前言
前言 为什么要撰写这样一个教程呢? 深入学习Jmeter 温故而知新,通过编写教程,我将更深入地学习JMeter.尽管我已经使用JMeter很长时间,但还有许多元件我并不十分了解.为了创作一个详尽且实 ...
- Dll堆栈问题(Dll的静态变量与全局变量、vs的MT与MD)
问题引入:dll有一个导出函数,函数参数是string&,string在函数内部被=赋值.在exe动态加载此dll,调用此导出函数后,会崩溃. 原因:如果任何STL类的实现中使用了静态变量(我 ...
- C# 证件照替换底色、设置背景图
软件说明 基于以下开源项目,做了再次封装 PaddleSegSharp: 本项目是一个基于百度飞桨PaddleSeg项目的人像分割模块而开发的.NET的工具类库.PaddleSeg是基于飞桨Paddl ...
- 可变形卷积系列(二) MSRA提出升级版DCNv2,变形能力更强 | CVPR 2019
论文提出DCNv2,不仅对DCNv1的结构进行了改进,还使用了有效的蒸馏学习策略,使得性能有很大的提升,各个方面都值得借鉴 来源:晓飞的算法工程笔记 公众号 论文: Deformable Conv ...
- KingbaseES 优化之sql优化方法
金仓数据库在sql层面提供了多种优化手段,但是这些的前提时需要保证我们的统计信息准确,优化器已经在正确信息下选择了它认为的最优的执行计划, 优化手段包括 •使用索引 索引解决的问题用于在进行表的扫描时 ...
- KingbaseES V8R3 集群运维案例 --操作系统‘soft lockup’引起的failover切换
案例说明: 在国产中标麒麟系统生产环境中,监控发现KingbaseES V8R3集群发生了failover的主备切换,客户需要给出分析报告,说明此次集群发生failover切换的原因,本次文档通过分析 ...
- #最大密度子图,0/1分数规划#UVA1389 Hard Life
题目 \(n\) 个点,\(m\) 条边的一个无向图,问导出子图的边数除以点数的最大值 分析 考虑二分这个答案,也就是0/1分数规划之后转换成 \(E-mid*V>0\) 这个问题虽然可以精确到 ...
- #Dijkstra#洛谷 4943 密室
题目 分析 考虑答案只可能是分别到或者哈利一个人到两个房间, 那么在罗恩的时候先不建不可走的边,等到哈利走的时候再建边 代码 #include <cstdio> #include < ...