NET中dictionary的一个小坑
2019独角兽企业重金招聘Python工程师标准>>>
问题描述:前段时间做个东西,打算在dictionary上按顺序扫描,不复合key条件的元素移动到末尾,然后减少计数,计算下 一个元素。目的就是一遍扫描实现对key的分组处理,减少遍历次数。然而程序表现与预想中不一致,表现
出来 就 是移除再插入的顺序和处理前的顺序一致。
复现后的场景:
移除顺序对添加的顺序有影响。
原因:
产生这个问题的原因在于Dictionary内部的实现机制,简单来说dictionary中维护了一个bucket数组和entry数组,
前者用于key的hash定位,后者负责数据存储,一个freelist维护了一个当前空位入口。至于细节请参考这篇博客
http://www.cnblogs.com/1-2-3/archive/2010/10/25/generic-dictionary-source-part2.html
查看源码中移除代码:
public bool Remove(TKey key) { if(key == null) { ThrowHelper.ThrowArgumentNullException(ExceptionArgument.key);} if (buckets != null) { int hashCode = comparer.GetHashCode(key) & 0x7FFFFFFF; int bucket = hashCode % buckets.Length; int last = -1; for (int i = buckets[bucket]; i >= 0; last = i, i = entries[i].next){ if (entries[i].hashCode == hashCode && comparer.Equals(entries[i].key, key)) { if (last < 0) { buckets[bucket] = entries[i].next;} else { entries[last].next = entries[i].next;} entries[i].hashCode = -1; entries[i].next = freeList; entries[i].key = default(TKey); entries[i].value = default(TValue); freeList = i; freeCount++; version++; return true;}}} return false;}
字典每次移除都会清空当前entry并将entry并入空闲索引链接中,指针指向上一个空位,当前entry作为索引链接的入口。
Add的方法源码截取:
int index; if (freeCount > 0) { index = freeList; freeList = entries[index].next; freeCount--;} else { if (count == entries.Length){ Resize(); targetBucket = hashCode % buckets.Length;} index = count; count++;} entries[index].hashCode = hashCode; entries[index].next = buckets[targetBucket]; entries[index].key = key; entries[index].value = value; buckets[targetBucket] = index; version++;
代码中首先需要获取到空闲位置,index=freeList中获取了最近移除的位置。后边对这个entry进行赋值了。
在看dictionary中获取顺序的代码截取:
while ((uint)index < (uint)dictionary.count) { if (dictionary.entries[index].hashCode >= 0) { current = new KeyValuePair<TKey, TValue>(dictionary.entries[index].key, dictionary.entries[index].value); index++; return true;}}
位置是在enrties块上面进行顺序读取的。
分析:
结合三段代码分析,当移除一个键的时候,当前块会成为空白块的入口,再次添加键的时候会重新占据这个位置。这可以解释我碰到的死循环问题。
再来解释复现的情况:
图解中可以看出这种情况的原因。结果符合预期的。dictionary中的顺序是不可信任的,如果一定要使用,需要考虑全面些。
转载于:https://my.oschina.net/hunjixin/blog/668531
NET中dictionary的一个小坑相关推荐
- firefox 中碰到的一个小坑
情况描述: 在一个处于正常文档流的div中,里面有一部分文字,还有个有浮动的块, 上代码 HTML: <div class="container"> this i ...
- mysql内核测试,MySQL 5.7内核复制中的一个小坑
问题背景 最近在写一个作为MySQL Slave的角色的程序,连接到MySQL Master使用MySQL复制协议来Dump Binlog事件流.很自然,这个程序在第一次运行的时候,其事务GTIDSe ...
- [LeetCode]29 两数相除和一个小坑点
给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符.返回被除数 dividend 除以除数 divisor 得到的商.示例 1:输入: ...
- parallel的一个小坑
parallel介绍 parallel是一个很好用的linux并行软件,与linux自带的xargs功能类似,但比它更好用,关于parallel的安装及具体用法可以参考该文章:15分钟神器gnu pa ...
- golang原生库mime/multipart上传formdata文件的一个小坑unexpected EOF
golang原生库mime/multipart上传formdata文件的一个小坑unexpected EOF 遇到的问题 问题代码 问题分析 正确代码 总结 遇到的问题 用mime/multipart ...
- c 语言for 循环大到小,C语言中for循环问题(一个小坑需注意)
今天分享一下C语言中的for循环中我们常常忽略的小问题. 举一个小例子来说明,大家也可以自己先算一下哦 #define _CRT_SECURE_NO_WARNINGS #include #includ ...
- Rocksdb Slice使用中的一个小坑
本文记录一下使用Rocksdb Slice过程中的一个小小坑,差点没一口老血吐出来. rocksdb的Slice 数据结构是一个小型得不可变类string数据结构,设计出来的目的是为了保证rocksd ...
- 集合覆盖模型例题_在打CodeForces的过程中发现的一个小模型
不久前的Grakn Forces 2020上,我想出了这个方法,我本来以为这个模型不会很常见.然而,今天的CodeForces #679 Div2上,我第二次碰到了可以用这个模型解决的问题,气人的是, ...
- js中使用shiro标签的一个小坑
在jsp页面中使用shiro标签很简单 <shiro:haspermission name="你的权限"> 你的标签 </shiro:haspermission& ...
最新文章
- FutureTask使用
- mysql循环insert多条数据
- 识别波峰波谷算法_马丁普林格:波峰-波谷演进法
- java中如何合并两个网格,Hazelcast: Java分布式内存网格框架(平台)
- 中文名称:深入浅出SQL
- easyui的datagrid和panel如何让标题动态改变?
- Linux| |对于UDP的学习
- AcWing 1945. 奶牛棒球(枚举+二分)
- python 绘图sns.distplot
- 神州数码云平台基础环境搭建
- R语言——查看内置数据集
- hdu5820 Lights
- 简练网软考知识点整理-易混概念项目绩效评估与团队绩效评价
- 【心情随笔】2021年终总结
- 黑科技新添成员, 小米mix5再次创新, 但这些真的只是黑科技的全部吗?
- javaweb仓库管理系统的实现,基于ssm+mysql实现的WMS进销存出库入库系统
- photoshop去眼袋
- 区块链技术相关知识笔记
- 专访Polychain创始人Olaf:我们只囤币,从不做空
- 【错误解决】can not be used when making a PIE object; recompile with -fPIC
热门文章
- postgresql 删除触发器_postgresql 触发器
- python多分类画roc曲线_利用python制作ROC曲线进行多分类
- redis配置文件conf详解
- 动环监控调试线_电力综合监控系统解决方案-【斯必得智慧物联】
- bootstrap 生日选择_bootstrap的datetimepicker只选择月份
- 绘制多个折线图_精品图表 | Excel绘制面板折线图
- cygwin安装好了如何添加cmake make_在windows上使用cmake
- 接收不到其他机器发来的报文_TCP/IP报文格式,康康就知道了
- java 泛型 泛型擦除(type erasure)
- python threading.lock