我可以从该字典的枚举循环中删除 ConcurrentDictionary 中的项目吗?

2023-12-29

例如:

ConcurrentDictionary<string,Payload> itemCache = GetItems();

foreach(KeyValuePair<string,Payload> kvPair in itemCache)
{
    if(TestItemExpiry(kvPair.Value))
    {   // Remove expired item.
        itemCache.TryRemove(kvPair.Key, out Payload removedItem);
    }
}

显然,对于普通的 Dictionary 这将引发异常,因为删除项目会在枚举生命周期内更改字典的内部状态。据我了解,ConcurrentDictionary 的情况并非如此,因为提供的 IEnumerable 处理内部状态更改。我这样理解对吗?有更好的模式可以使用吗?


对我来说很奇怪的是,你现在收到了两个似乎证实你不能这样做的答案。我刚刚自己测试了它,它工作得很好,没有抛出任何异常。

下面是我用来测试行为的代码,后面是输出的摘录(大约是当我按“C”清除字典中的字典时)foreach and S之后立即停止后台线程)。请注意,我对此施加了相当大的压力ConcurrentDictionary:16 个线程计时器,每个计时器大约每 15 毫秒尝试添加一个项目。

在我看来,这个类非常强大,如果您在多线程场景中工作,那么值得您关注。

Code

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;

namespace ConcurrencySandbox {
    class Program {
        private const int NumConcurrentThreads = 16;
        private const int TimerInterval = 15;

        private static ConcurrentDictionary<int, int> _dictionary;
        private static WaitHandle[] _timerReadyEvents;
        private static Timer[] _timers;
        private static volatile bool _timersRunning;

        [ThreadStatic()]
        private static Random _random;
        private static Random GetRandom() {
            return _random ?? (_random = new Random());
        }

        static Program() {
            _dictionary = new ConcurrentDictionary<int, int>();
            _timerReadyEvents = new WaitHandle[NumConcurrentThreads];
            _timers = new Timer[NumConcurrentThreads];

            for (int i = 0; i < _timerReadyEvents.Length; ++i)
                _timerReadyEvents[i] = new ManualResetEvent(true);

            for (int i = 0; i < _timers.Length; ++i)
                _timers[i] = new Timer(RunTimer, _timerReadyEvents[i], Timeout.Infinite, Timeout.Infinite);

            _timersRunning = false;
        }

        static void Main(string[] args) {
            Console.Write("Press Enter to begin. Then press S to start/stop the timers, C to clear the dictionary, or Esc to quit.");
            Console.ReadLine();

            StartTimers();

            ConsoleKey keyPressed;
            do {
                keyPressed = Console.ReadKey().Key;
                switch (keyPressed) {
                    case ConsoleKey.S:
                        if (_timersRunning)
                            StopTimers(false);
                        else
                            StartTimers();

                        break;
                    case ConsoleKey.C:
                        Console.WriteLine("COUNT: {0}", _dictionary.Count);
                        foreach (var entry in _dictionary) {
                            int removedValue;
                            bool removed = _dictionary.TryRemove(entry.Key, out removedValue);
                        }
                        Console.WriteLine("COUNT: {0}", _dictionary.Count);

                        break;
                }

            } while (keyPressed != ConsoleKey.Escape);

            StopTimers(true);
        }

        static void StartTimers() {
            foreach (var timer in _timers)
                timer.Change(0, TimerInterval);

            _timersRunning = true;
        }

        static void StopTimers(bool waitForCompletion) {
            foreach (var timer in _timers)
                timer.Change(Timeout.Infinite, Timeout.Infinite);

            if (waitForCompletion) {
                WaitHandle.WaitAll(_timerReadyEvents);
            }

            _timersRunning = false;
        }

        static void RunTimer(object state) {
            var readyEvent = state as ManualResetEvent;
            if (readyEvent == null)
                return;

            try {
                readyEvent.Reset();

                var r = GetRandom();
                var entry = new KeyValuePair<int, int>(r.Next(), r.Next());
                if (_dictionary.TryAdd(entry.Key, entry.Value))
                    Console.WriteLine("Added entry: {0} - {1}", entry.Key, entry.Value);
                else
                    Console.WriteLine("Unable to add entry: {0}", entry.Key);

            } finally {
                readyEvent.Set();
            }
        }
    }
}

输出(摘录)

cAdded entry: 108011126 - 154069760   // <- pressed 'C'
Added entry: 245485808 - 1120608841
Added entry: 1285316085 - 656282422
Added entry: 1187997037 - 2096690006
Added entry: 1919684529 - 1012768429
Added entry: 1542690647 - 596573150
Added entry: 826218346 - 1115470462
Added entry: 1761075038 - 1913145460
Added entry: 457562817 - 669092760
COUNT: 2232                           // <- foreach loop begins
COUNT: 0                              // <- foreach loop ends
Added entry: 205679371 - 1891358222
Added entry: 32206560 - 306601210
Added entry: 1900476106 - 675997119
Added entry: 847548291 - 1875566386
Added entry: 808794556 - 1247784736
Added entry: 808272028 - 415012846
Added entry: 327837520 - 1373245916
Added entry: 1992836845 - 529422959
Added entry: 326453626 - 1243945958
Added entry: 1940746309 - 1892917475

另请注意,根据控制台输出,它看起来像foreach循环锁定了试图向字典添加值的其他线程。 (我可能是错的,但否则我猜你会在“COUNT”行之间看到一堆“添加条目”行。)

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

我可以从该字典的枚举循环中删除 ConcurrentDictionary 中的项目吗? 的相关文章

随机推荐

  • 如果不在引号之间则按空格分割

    我试过这个 但没有成功 我还能做什么来让它发挥作用 顺便说一句 我使用java的string split 尝试这个 仅当这些空格后跟零或偶数个引号 一直到字符串末尾 时 才会拆分为一个或多个空格 以下演示 public class Main
  • iPhone 上的 YouTube 视频 PhoneGap 应用程序

    很抱歉再次回到这个话题 但我真的很沮丧 我阅读了我找到的所有资源 在网上搜索 但我无法对我的问题提出明确的答案 问题描述我正在使用phonegap 1 0 创建一个iphone 应用程序 在此应用程序中 一个选项卡专门用于来自我的 YouT
  • TYPO3:禁用特定插件/扩展的缓存

    我构建了一个扩展和一个插件 前端用户可以在其中编辑他们的个人资料 但我注意到一个关键问题 在 编辑个人资料 下 用户可以看到有关甚至未登录的其他用户的完整信息 显然该表单已缓存在服务器上 因为添加后 config no cache 1 它没
  • 在 laravel 5.3 中添加 css 和 js 文件

    我想在单页中包含 css 所有 css 和 js 并将其加载到所有页面中 现在 如果我想在欢迎页面中包含 bootstrap css 和 bootstrap js 我已包含在welcome blade php 页面中 如果我想要添加另一个页
  • AttributeError:模块“tensorflow.contrib.learn”没有属性“TensorFlowDNNClassifier”

    这是我尝试执行的 ml 张量流代码 import tensorflow contrib learn as skflow from sklearn import datasets metrics iris datasets load iris
  • 访问 Node.js Express 中的 HTTP 服务器对象

    我在中间件内 function req res next 有没有办法从 HTTP 服务器对象访问req UPDATE 让我说得更具体一些 我试图找出服务器侦听的端口 或者 unix 套接字路径 如果它正在侦听 在你的主应用程序文件中怎么样
  • Eclipse 中适用于匈牙利风格成员的 Getter 和 Setter

    我正在从事的项目规定了类成员变量的匈牙利表示法 例子 String m foo 是否可以让 Eclipse 在生成 getter 和 setter 时去掉匈牙利前缀 我正在使用 Helios 它表明 毫不奇怪 getM foo and se
  • Qt 避免警告“QProcess:进程仍在运行时被破坏”

    最简单的代码 void test QProcess p p start sleep 10 p waitForBytesWritten p waitForFinished 1 当然 该过程无法在函数结束之前完成 因此它会显示一条警告消息 QP
  • 在datagridview中搜索数据

    我有一个 datagridview 显示数据库表中的数据 有两列 ID 和 NAME 我有一个文本框 在其中输入名称 这些名称的数据显示在 datagridview 中 我已经实现了数据搜索 但我想像在组合框中那样进行搜索 当我输入 a 时
  • boost的shared_ptr(shared_ptr const & r, T * p)有什么用?

    boost shared ptr有一个不寻常的构造函数 template
  • WP7 Mp3MediaStreamSource 演示无法正常工作

    我下载了 Mp3 MediaStreamSource 演示http archive msdn microsoft com ManagedMediaHelpers http archive msdn microsoft com Managed
  • 将 Facebook 粉丝页面嵌入 Android 应用程序的视图中

    我的 Android 应用程序由一个简单的选项卡布局 3 个选项卡 组成 假设用户选择选项卡 2 现在我想向用户展示一个特定的粉丝页面 只是最近的帖子 更新 如果它可以直接嵌入到选项卡下方的视图中 那就最好了 没有弹出窗口 对话框 我知道
  • TCL 电子邮件脚本无法在 Activestate TCL 中发送

    我在 MAC OSX 版本的 TCL 上运行了以下脚本 它工作正常 但它挂在 Windows 7 计算机上的 ActiveState TCL 上 proc send simple message recipient email server
  • 数值回归测试

    我正在编写科学计算代码 用 C 编写 除了对较小的组件执行单元测试之外 我还想通过与 已知良好 的比较来对某些数值输出进行回归测试之前修订版的答案 我想要一些功能 允许将数字与指定的容差进行比较 对于舍入误差和宽松的期望 能够区分整数 双精
  • 带有 css 多列的有序列表号

    我正在使用默认编号创建一个有序列表 该列表将超过 300 个 我使用 css column count 将列表分为几列 但默认列表编号仅适用于第一列 有没有办法获得多列中整个列表的编号 请检查FIDDLE https jsfiddle ne
  • 为什么我收到“未定义不是对象(评估 PropTypes.shape)”?

    每当我尝试运行我的iOS模拟器 我收到这个错误 所有模块均已安装 图片的文件路径正确 除了模拟器中出现的错误外 IDE 中没有抛出任何错误 下图为错误 Here s Login js import React Component from
  • 如何返回 R 中序列的行索引? [复制]

    这个问题在这里已经有答案了 我正在尝试找到序列的行位置 我的意思是 x lt c 1 1 y lt c 1 1 1 0 1 0 0 match x y 1 2 1 为什么不返回 2 3 这就是我想要它做的 如果我这样做 y lt c 0 1
  • 为 Android HTTP 请求创建 Google HTTP 传输对象

    我正在创建一个 Android 应用程序并尝试通过 Google API 客户端使用 Google Places API 我一直在关注这个例子 http ddewaele blogspot com 2011 05 introducing g
  • Ajax 功能在移动浏览器上无法使用

    您好 感谢您查看此内容 对 jQuery ajax 等非常陌生 该网站可以通过 FTP 访问相应的服务器 因此我 据我所知 没有违反跨域策略 该网站在任何桌面浏览器上都可以正常工作 但不适用于任何移动浏览器 我觉得问题很明显 但我不知道该怎
  • 我可以从该字典的枚举循环中删除 ConcurrentDictionary 中的项目吗?

    例如 ConcurrentDictionary