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的一个小坑相关推荐

  1. firefox 中碰到的一个小坑

    情况描述: 在一个处于正常文档流的div中,里面有一部分文字,还有个有浮动的块, 上代码 HTML: <div class="container">    this i ...

  2. mysql内核测试,MySQL 5.7内核复制中的一个小坑

    问题背景 最近在写一个作为MySQL Slave的角色的程序,连接到MySQL Master使用MySQL复制协议来Dump Binlog事件流.很自然,这个程序在第一次运行的时候,其事务GTIDSe ...

  3. [LeetCode]29 两数相除和一个小坑点

    给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符.返回被除数 dividend 除以除数 divisor 得到的商.示例 1:输入: ...

  4. parallel的一个小坑

    parallel介绍 parallel是一个很好用的linux并行软件,与linux自带的xargs功能类似,但比它更好用,关于parallel的安装及具体用法可以参考该文章:15分钟神器gnu pa ...

  5. golang原生库mime/multipart上传formdata文件的一个小坑unexpected EOF

    golang原生库mime/multipart上传formdata文件的一个小坑unexpected EOF 遇到的问题 问题代码 问题分析 正确代码 总结 遇到的问题 用mime/multipart ...

  6. c 语言for 循环大到小,C语言中for循环问题(一个小坑需注意)

    今天分享一下C语言中的for循环中我们常常忽略的小问题. 举一个小例子来说明,大家也可以自己先算一下哦 #define _CRT_SECURE_NO_WARNINGS #include #includ ...

  7. Rocksdb Slice使用中的一个小坑

    本文记录一下使用Rocksdb Slice过程中的一个小小坑,差点没一口老血吐出来. rocksdb的Slice 数据结构是一个小型得不可变类string数据结构,设计出来的目的是为了保证rocksd ...

  8. 集合覆盖模型例题_在打CodeForces的过程中发现的一个小模型

    不久前的Grakn Forces 2020上,我想出了这个方法,我本来以为这个模型不会很常见.然而,今天的CodeForces #679 Div2上,我第二次碰到了可以用这个模型解决的问题,气人的是, ...

  9. js中使用shiro标签的一个小坑

    在jsp页面中使用shiro标签很简单 <shiro:haspermission name="你的权限"> 你的标签 </shiro:haspermission& ...

最新文章

  1. FutureTask使用
  2. mysql循环insert多条数据
  3. 识别波峰波谷算法_马丁普林格:波峰-波谷演进法
  4. java中如何合并两个网格,Hazelcast: Java分布式内存网格框架(平台)
  5. 中文名称:深入浅出SQL
  6. easyui的datagrid和panel如何让标题动态改变?
  7. Linux| |对于UDP的学习
  8. AcWing 1945. 奶牛棒球(枚举+二分)
  9. python 绘图sns.distplot
  10. 神州数码云平台基础环境搭建
  11. R语言——查看内置数据集
  12. hdu5820 Lights
  13. 简练网软考知识点整理-易混概念项目绩效评估与团队绩效评价
  14. 【心情随笔】2021年终总结
  15. 黑科技新添成员, 小米mix5再次创新, 但这些真的只是黑科技的全部吗?
  16. javaweb仓库管理系统的实现,基于ssm+mysql实现的WMS进销存出库入库系统
  17. photoshop去眼袋
  18. 区块链技术相关知识笔记
  19. 专访Polychain创始人Olaf:我们只囤币,从不做空
  20. 【错误解决】can not be used when making a PIE object; recompile with -fPIC

热门文章

  1. postgresql 删除触发器_postgresql 触发器
  2. python多分类画roc曲线_利用python制作ROC曲线进行多分类
  3. redis配置文件conf详解
  4. 动环监控调试线_电力综合监控系统解决方案-【斯必得智慧物联】
  5. bootstrap 生日选择_bootstrap的datetimepicker只选择月份
  6. 绘制多个折线图_精品图表 | Excel绘制面板折线图
  7. cygwin安装好了如何添加cmake make_在windows上使用cmake
  8. 接收不到其他机器发来的报文_TCP/IP报文格式,康康就知道了
  9. java 泛型 泛型擦除(type erasure)
  10. python threading.lock