gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 08:38:35 24 4
gpt4 key购买 nike

例如:

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”来清除 foreachS 中的字典以停止后台线程时)。请注意,我对这个 ConcurrentDictionary 施加了相当大的压力。 :16 个线程计时器,每个线程大约每 15 毫秒尝试添加一个项目。

在我看来,这个类非常健壮,如果您在多线程场景中工作,则值得您关注。

代码

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”行之间看到一堆“Added entry”行。)

关于.net - 我可以从该字典的枚举循环中删除 ConcurrentDictionary 中的项目吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2318005/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com