【发布时间】:2021-02-09 11:10:31
【问题描述】:
我有一个要清空的 ConcurrentDictionary,将其内容复制到字典(或任何其他容器)中,同时清空它。
一个关键的不变性是在操作过程中不会丢失源中的任何元素。
我当前的代码如下所示:
private Dictionary<TKey, TValue> Foo<TKey, TValue>(ConcurrentDictionary<TKey, TValue> source)
{
var result = new Dictionary<TKey, TValue>();
foreach (var item in source)
{
result[item.Key] = item.Value;
}
source.Clear();
return result;
}
据我了解,这段代码是线程安全的,但在 foreach 循环之后和 Clear() 之前同时添加的任何元素都将被清除。
编辑:更精确一些。在我的用例中,该代码是唯一删除某些字典键的代码;其他线程只使用 TryAdd 或 AddOrUpdate。
【问题讨论】:
-
你为什么要这个?
-
您可以使用 .ToDictionary() 方法复制项目,但您仍然需要阻止源字典写入,即在“writer”方法中添加一些标志,以防止它在您输入时输入正在复制。您可以即声明一个“volatile”布尔字段用作标志
-
@mjwills
ImmutableDictionary可能会比ConcurrentDictionary慢约 10 倍,而且分配也明显更多。它也不是并发的。每次更新时都需要同步。如果 OP 想要获取其值并经常清除它,这可能是一个有趣的解决方案,因为拍摄不可变集合的快照基本上是免费的。 -
那么
ToArray和 docs.microsoft.com/en-us/dotnet/api/… 会很好地满足您的需求。这允许您克隆字典,然后仅从原始字典中删除与您的克隆匹配的条目。 -
The invariant corresponds to the requirement that all collected values are logged at some point.请注意,您并没有严格地满足这个标准 - 因为如果两个对同一个键的写入连续发生,您不一定会记录第一个.或许考虑两个数据结构——并发字典存储数据,并发队列记录数据?
标签: c# concurrency concurrentdictionary