Dictionary 和 ConcurrentDictionary 之间修改集合时的不同行为

2023-12-07

使用如下所示的正常字典代码,我得到的异常是

集合已修改;枚举操作可能无法执行。

Dictionary<int, int> dict2 = new Dictionary<int, int>();
dict2.Add(1, 10);
dict2.Add(2, 20);
dict2.Add(3, 30);
dict2.Add(4, 40);

foreach (var d in dict2)
{
    if (dict2.ContainsKey(2))
        dict2.Remove(2);

    if (dict2.ContainsKey(3))
        dict2.Remove(3);
}

然而对于 ConcurrentDictionary,这工作得很好。

ConcurrentDictionary<int, int> dict1 = new ConcurrentDictionary<int, int>();
dict1.AddOrUpdate(1, 10, (k,v)=> 10);
dict1.AddOrUpdate(2, 20, (k, v) => 20);
dict1.AddOrUpdate(3, 30, (k,v)=> 30);
dict1.AddOrUpdate(4, 40, (k,v)=> 40);

foreach (var d in dict1)
{
    int x;
    if (dict1.ContainsKey(2))
        dict1.TryRemove(2, out x);

    if (dict1.ContainsKey(3))
        dict1.TryRemove(3, out x);
}

为什么行为上会有差异?


原因是Dictionary和ConcurrentDictionary有不同的用途。 ConcurrentDictionary - 应该处理并发问题(从不同线程编辑),而 Dictionary 将为您提供更好的性能。

不同行为的原因是:GetEnumerator() 方法的实现不同。

现在我将解释 Dictionary 出现异常的原因以及 ConcurrentDictionary 没有出现异常的原因。

foreach 语句是类似以下内容的语法糖:

    var f = dict.GetEnumerator();

        while (f.MoveNext())
        {
            var x = f.Current;

            // your logic
        }

字典中的“GetEnumerator()”返回名为“Enumerator”的结构的新实例

该结构实现: IEnumerator >KeyValuePair>TKey,TValue>>,IDictionaryEnumerator 和他的 C'tor 如下所示:

        internal Enumerator(Dictionary<TKey,TValue> dictionary, int getEnumeratorRetType) {
            this.dictionary = dictionary;
            version = dictionary.version;
            index = 0;
            this.getEnumeratorRetType = getEnumeratorRetType;
            current = new KeyValuePair<TKey, TValue>();
        }

“Enumerator”中 MoveNext() 的实现首先验证源字典是否未被修改:

      bool moveNext(){
            if (version != dictionary.version) {
                throw new InvalidOperationException....
            }
            //the itarate over...
      }

ConcurrentDictionary 中的“GetEnumerator()”实现了一种不同的方式:

   IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator(){
         Node[] buckets = m_tables.m_buckets;

         for (int i = 0; i < buckets.Length; i++)
         {

             Node current = Volatile.Read<Node>(ref buckets[i]);

             while (current != null)
             {
                 yield return new KeyValuePair<TKey, TValue>(current.m_key,  current.m_value);
                 current = current.m_next;
             }
         }
    }

在此实现中,有一种称为“惰性求值”的技术,return 语句将返回值。 当消费者调用 MoveNext() 时,您将返回“current = current.m_next;” 因此,GetEnumerator() 内部不存在“不改变”验证。

如果你想避免“字典编辑”出现异常,那么: 1. 迭代到要删除的元素 2. 删除元素 3. 在调用 MoveNext() 之前中断

在你的例子中:

        foreach (var d in dict2)
        {
            if (dict2.ContainsKey(1))
                dict2.Remove(1);

            if (dict2.ContainsKey(3))
                dict2.Remove(3);

            break; // will prevent from exception
        }

有关 ConcurrentDictionary 的 GetEnumerator() 的更多信息:https://msdn.microsoft.com/en-us/library/dd287131(v=vs.110).aspx

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Dictionary 和 ConcurrentDictionary 之间修改集合时的不同行为 的相关文章

  • C#.Net 邮件将进入垃圾邮件文件夹

    我正在从 ASP net Web 应用程序发送电子邮件 邮件发送成功 没有失败 但大多数都进入了垃圾邮件文件夹 请帮助我克服垃圾邮件过滤器 我的发送邮件代码 public void SendMail string FromAddress s
  • C# 中的 Stack<> 实现

    我最近一直在实现递归目录搜索实现 并且使用堆栈来跟踪路径元素 当我使用 string Join 连接路径元素时 我发现它们被颠倒了 当我调试该方法时 我查看了堆栈 发现堆栈内部数组中的元素本身是相反的 即最近 Push 的元素位于内部数组的
  • Selenium - C# - Webdriver - 无法找到元素

    在 C 中使用 selenium 我试图打开浏览器 导航到 Google 并找到文本搜索字段 我尝试下面的 IWebDriver driver new InternetExplorerDriver C driver Navigate GoT
  • Python将文本文件解析为嵌套字典

    考虑以下数据结构 HEADER1 key value key value HEADER2 key value key value HEADER3 key value HEADER4 key value key value 原始数据中没有缩进
  • JavaScript 错误:MVC2 视图中的条件编译已关闭

    我试图在 MVC2 视图页面中单击时调用 JavaScript 函数 a href Select a JavaScript 函数 function SelectBenefit id code alert id alert code 这里 b
  • Unity手游触摸动作不扎实

    我的代码中有一种 错误 我只是找不到它发生的原因以及如何修复它 我是统一的初学者 甚至是统一的手机游戏的初学者 我使用触摸让玩家从一侧移动到另一侧 但问题是我希望玩家在手指从一侧滑动到另一侧时能够平滑移动 但我的代码还会将玩家移动到您点击的
  • 条件类型定义

    如果我有一小段这样的代码 template
  • wordexp 失败时我们需要调用 wordfree 吗?

    wordexp 失败时我们需要调用 wordfree 吗 在某些情况下 调用 wordfree 似乎会出现段错误 例如 当 wordfree 返回字符串为 foo bar 的错误代码时 这在手册页中并不清楚 我已经看到在某些错误情况下使用了
  • Unity c# 四元数:将 y 轴与 z 轴交换

    我需要旋转一个对象以相对于现实世界进行精确旋转 因此调用Input gyro attitude返回表示设备位置的四元数 另一方面 这迫使我根据这个四元数作为默认旋转来计算每个旋转 将某些对象设置为朝上的简单方法如下 Vector3 up I
  • 我们可以通过指针来改变const定义的对象的值吗?

    include
  • 如何从 Boost.PropertyTree 复制子树

    我有一些boost property tree ptree 我需要树来删除一些具有特定标签名称的元素 例如 xml 表示源ptree如下
  • 当Model和ViewModel一模一样的时候怎么办?

    我想知道什么是最佳实践 我被告知要始终创建 ViewModel 并且永远不要使用核心模型类将数据传递到视图 这就说得通了 让我把事情分开 但什么是Model 和ViewModel一模一样 我应该重新创建另一个类还是只是使用它 我觉得我应该重
  • Xamarin Forms Binding - 访问父属性

    我无法访问页面的 ViewModel 属性以便将其绑定到 IsVisible 属性 如果我不设置 BindingContext 我只能绑定它 有没有办法可以在设置 BindingContext 的同时访问页面的 viewmodel root
  • 如何在C#中控制datagridview光标移动

    我希望 datagridview 光标向右移动到下一列 而不是在向单元格输入数据后移动到下一行 我试图通过 dataGridView1 KeyDown 事件捕获键来控制光标 但这并不能阻止光标在将数据输入到单元格后移动到下一行 提前感谢你的
  • 如何高效计算连续数的数字积?

    我正在尝试计算数字序列中每个数字的数字乘积 例如 21 22 23 98 99 将会 2 4 6 72 81 为了降低复杂性 我只会考虑 连续的数字 http simple wikipedia org wiki Consecutive in
  • 如何从 Windows Phone 7 模拟器获取数据

    我有一个 WP7 的单元测试框架 它在手机上运行 结果相当难以阅读 因此我将它们写入 XDocument 我的问题是 如何才能将这个 XML 文件从手机上移到我的桌面上 以便我可以实际分析结果 到目前为止 我所做的是将 Debugger B
  • 任何人都可以清楚地告诉如何在不使用像 这样的预定义函数的情况下找到带有小数值或小数值的指数吗? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 例如 2 0 5 1 414 所以想要 我是 c 的新手 所以请解释简单的逻辑 如果不是复杂的逻辑也足够了 在数学中 从整数取幂到实数
  • .Net Reactive Extensions Framework (Rx) 是否考虑拓扑顺序?

    Net 反应式扩展框架是否按拓扑顺序传播通知以最大限度地减少更新量 就像 Scala Rx 所做的那样 Net 反应式扩展 Rx 是否可以 https github com lihaoyi scala rx wiki How it Work
  • 如何在 ASP.NET Core 中注入泛型的依赖关系

    我有以下存储库类 public class TestRepository Repository
  • 嵌入式linux编写AT命令

    我在向 GSM 模块写入 AT 命令时遇到问题 当我使用 minicom b 115200 D dev ttySP0 term vt100 时它工作完美 但我不知道如何在 C 代码中做同样的事情 我没有收到任何错误 但模块对命令没有反应 有

随机推荐

  • TCP 和 UDP 协议意义上的记录或数据边界是什么意思?

    我正在学习套接字并在中找到了 数据或记录边界 一词SOCK SEQPACKET通讯协议 任何人都可以用简单的话解释什么是数据边界以及如何SOCK SEQPACKET不同于SOCK STREAM SOCK DGRAM 这个答案https st
  • 有没有办法在运行时查看 Entity Framework Code First 的列映射?

    我正在尝试编写 Entity Framework Code First 的附加组件 并且需要一种在运行时获取模型列的配置的方法 例如 这是代码设置OnModelCreating by the DbModelBuilder builder E
  • 将记录集传递给函数而不是单个变量有什么缺点吗?

    我们有一个单用户 Access 2007 数据库 它可以执行诸如发送报告和根据计时器 事件 更新其他数据库之类的操作 一次一个事件 执行每个事件时 都会创建一个单行记录集 其中包含该事件运行所需的信息 我一直使用单个变量以通常的方式将参数传
  • Jupyter Notebook 500:内部服务器错误

    我想学习如何使用 Jupyter Notebook 到目前为止 我已经成功下载并安装了它 使用 pip 但我在打开它时遇到了问题 我通过输入以下内容打开它 jupyter notebook 在我的终端中 它在我的浏览器中打开 网址为 htt
  • WorkManager:如何在同一个应用程序中设置不同的WorkManager配置

    我正在开发一个多模块项目 Gradle 模块 我在我的模块中使用 WorkManager 我还使用 Dagger 进行依赖注入 现在我必须使用 dagger 将依赖项注入到我的 WorkManager 中 我非常熟悉 Dagger 2 与
  • 确定 Android GC 何时运行

    有谁知道是否有一种方法可以识别 在代码中 而不是 LogCat GC 何时运行 也许有意图被激发 我可以分析 LogCat 输出 但如果我能够确定 GC 何时从我的代码运行 那就更理想了 您可以使用弱引用技巧来做到这一点 WeakRefer
  • 连接间隔 核心蓝牙

    有没有办法通过Core Bluetooth更改连接间隔 我正在将数据块传输到外设 并且传输数据需要花费很多时间 我想减少这个时间 如果可以使用核心蓝牙从 iOS 写入或更新连接间隔 请告诉我 谢谢 仅通过将连接参数更新从外设发送到 iOS
  • 在 R 中合并具有缺失值的数据框

    获取数据帧的代码 rat all structure list frequency c 37L 31L 14L 11L 2L 3L isoforms 8 13 type structure c rat all rat all rat all
  • 在 R 的 data.table 中查找 foverlap 的一次迭代中的所有重叠

    我正在尝试使用 data table 合并 R 中的一堆重叠时间段 我有一个对表本身的 foverlap 的调用 这足够有效 我的问题是这样的 假设A期与B期重叠 B与C期重叠 但A不与C重叠 在这种情况下 A不与C分组 它们最终必须合并
  • Groupby 和 Pivot Pandas 表

    这应该很快 但是我正在做的枢轴 分组工作都没有达到我的需要 我有一个这样的表 Letter Period Amount YrMnth 2014 12 B 6 0 2014 12 C 8 1 2014 12 C 9 2 2014 12 C 1
  • 不显示背景图像的元素

    我正在尝试为 a 元素添加背景图像 但它只会显示图像的一部分 因此 如果我将 Home 作为值 则无论 home 占用的空间是什么 这就是图像的显示内容 如果该值是空它不会显示图像的任何内容 尽管我已经设置了要显示的 a 元素的宽度和高度
  • 解释 HTTP/1.1 标头字段值时使用什么编码

    在 HTTP 1 1 规范中 当涉及到定义标头时 我得到了这个 消息头 字段名称 字段值 字段值 字段内容 LWS field contet OCTET 和 TEXT 的定义是 OCTET TEXT 其中 CTL 指的是 US ASCII
  • 如何在delphi 7中释放字符串列表中的对象?

    下面是 Zarko Gajic 在 Delphi 的 TStrings 项目中释放对象的想法 在关于德尔福我使用的是 Delphi 7 TStringList 没有 OwnsObjects 运行以下代码会提示EaccessViolation
  • 向 .gitignore 添加新条目不起作用

    如果我理解正确的话 为了 忽略 一个文件 这样当我输入时它就不会出现git status or git add A我需要将其添加到 gitignore 文件中 我的目标是在向 Git 提交更改时永久忽略某个文件夹和文件 我尝试在编辑器中编辑
  • MongoDb / C# 过滤并获取所有子文档

    我在查询 Mongodb 集合时遇到困难 我正在使用的文档 public class Customer public ObjectId Id get set public int CustomerId get set public List
  • 如何在 datagridview 列中显示总和?

    我需要显示的总和count专栏从这里datagridview 但我不知道如何获取 datagridview 中的数据 当我点击按钮时 我想显示94 in label1 如何才能做到这一点 int sum 0 for int i 0 i lt
  • Ionic 取消硬后退按钮覆盖

    关于在 Ionic 中覆盖物理 Android BACK 按钮以提供自定义行为存在一些问题 Ionic 覆盖特定控制器的所有 后退 按钮行为 Ionic 如何覆盖后退按钮功能 但你如何取消覆盖恢复默认行为 我尝试更改处理程序的优先级 希望默
  • C3.js 从 CSV 中排除列

    我正在使用 C3 JS 通过从提供的 CSV 文件加载数据来创建多系列折线图 我可以绘制图表 但是我还没有发现是否可以仅绘制 CSV 中的某些列 我的图表正在绘制所有 CSV 列 我的 CSV 看起来像这样 Sex Age L M S P3
  • 使用 OpenDaylight 入门原型不起作用

    尝试跟随开放日光开发者教程获得在控制器上运行的初始 hello world 应用程序 但是运行命令 mvn archetype generate DarchetypeGroupId org opendaylight controller D
  • Dictionary 和 ConcurrentDictionary 之间修改集合时的不同行为

    使用如下所示的正常字典代码 我得到的异常是 集合已修改 枚举操作可能无法执行 Dictionary