在 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 无法稳定返回相同的对象

本文的代码放在githubgitee 欢迎访问

可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 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 获取到非预期的首项的更多相关文章

  1. 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` ...

  2. SQL-10 获取所有非manager的员工emp_no

    题目描述 获取所有非manager的员工emp_noCREATE TABLE `dept_manager` (`dept_no` char(4) NOT NULL,`emp_no` int(11) N ...

  3. [改善Java代码] 避免instanceof非预期结果

    建议18: 避免instanceof非预期结果 instanceof是一个简单的二元操作符,它是用来判断一个对象是否是一个类实例的,其操作类似于>=.==,非常简单,我们来看段程序,代码如下: ...

  4. int.TryParse非预期执行引发的思考 ASP.NET -- WebForm -- 给图片添加水印标记 Windows -- 使用批处理文件.bat删除旧文件

    int.TryParse非预期执行引发的思考   问题出现 这天在写一个页面,想谨慎些就用了int.TryParse,结果出问题了. 代码如下: Copy int id = 1000; //Reque ...

  5. 为什么委托的减法(- 或 -=)可能出现非预期的结果?(Delegate Subtraction Has Unpredictable Result)

    当我们为一个委托写 -= 的时候,ReSharper 会提示“Delegate Subtraction Has Unpredictable Result”,即“委托的减法可能出现非预期的结果”.然而在 ...

  6. dotnet C# 给结构体字段赋值非线程安全

    在 dotnet 运行时中,给引用对象进行赋值替换的时候,是线程安全的.给结构体对象赋值,如果此结构体是某个类的成员字段,那么此赋值不一定是线程安全的.是否线程安全,取决于结构体的大小,取决于此结构体 ...

  7. ReentrantLock获取到非公平锁的源码

    /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void l ...

  8. 警惕System.Environment.CurrentDirectory 获取当前目录

    最近工作中,要做个客户端提醒的小工具:winform程序自然少不了要读取和应用程序同一个目录的配置文件(不是exe.config文件): 要读取当前应用程序所在目录我立马想到了System.Envir ...

  9. java最全的获取某个接口或者某个类所有对应的所有实现类和继承类的工具类--反射动态获取、非动态获取、按照路径获取等总结

    我们直接上代码吧,代码中有注释说明. //直接看代码吧 import java.io.File; import java.lang.reflect.Field; import java.net.URL ...

  10. int.TryParse非预期执行引发的思考

    问题出现 这天在写一个页面,想谨慎些就用了int.TryParse,结果出问题了. 代码如下: int id = 1000; //Request.QueryString["id"] ...

随机推荐

  1. 初探修模的三维模型OBJ格式轻量化压缩的遇到常见问题与处理方法

    初探修模的三维模型OBJ格式轻量化压缩的遇到常见问题与处理方法 在对经过修模的三维模型进行OBJ格式轻量化压缩处理的过程中,可能会遇到一些常见问题.以下是一些常见问题以及相应的处理方法: 1.顶点丢失 ...

  2. TypeScript筑基笔记一:Visual Studio Code 创建Typescript文件和实时监控

    问题一:电脑如何安装Typescript? 答案:打开电脑cmd 输入以下指令: npm install -g typescript 中国电脑因为访问慢,可以先安装cnpm后再安装 安装cnpm指令 ...

  3. 在 PostgreSQL 中,解决图片二进制数据,由于bytea_output参数问题导致显示不正常的问题。

    在 PostgreSQL 中,bytea_output 参数控制在查询结果中 bytea 类型的显示格式.默认情况下,bytea_output 的值为 hex,这意味着在查询结果中,bytea 类型的 ...

  4. 动态水印也能去除?ProPainter一键视频抠图整合包下载

    ProPainter是一个基于E2FGVI实现的AI视频编辑工具,它结合了增强的传播和Transformer机制,能够快速高效地进行视频修复和水印去除 功能特点 · 对象移除:智能地检测和移除视频中的 ...

  5. 【UE插件DTRabbitMQ】 虚幻引擎蓝图连接RabbitMQ服务器使用插件说明

    本插件可以使用蓝图连接 RabbitMQ服务器,并推送或者监听消息. 下载地址地址在文章最后. 1. 节点说明 Create RabbitMQ Client - 创建RabbitMQ客户端对象 创建一 ...

  6. Oracle数据库对比MySQL

    基本 Oracle默认端口:1521 默认用户:system MySQL默认端口:3306 默认用户:root 连接MySQL: mysql -u root -p -- 输入密码 -- 查询所有数据库 ...

  7. java读写txt

    /** * 传入txt路径读取txt文件 * * @param txtPath * @return 返回读取到的内容 */ public String readTxt(String txtPath) ...

  8. matlab的基本操作

    matlab的基本操作 1.写在前面 最近在处理一些作业时用到了matlab,发现以前学习的语句已经忘得差不多了.现在找到以前的学习资料,重新复习一下.顺便总结一下知识点,以免下一次使用时又忘记了而又 ...

  9. FCOSv2:原作的扩展版本,小修小改,性能高达50.4AP | IEEE T-PAMI 2020

    本文是对FCOS的小修小改,最终性能达到了50.4AP,可谓相当强劲了,大家在工程上可以参考其中的改进以及提升方法   来源:晓飞的算法工程笔记 公众号 论文: FCOS: A Simple and ...

  10. KingbaseES V8R6 集群运维案例 -- 自动故障转移失败处理

    KingbaseES V8R6版本 数据库自动故障转移失败(Automatic Database Failover Fails) 适用于: KingbaseES V8R6 版本. repmgr配置信息 ...