【发布时间】:2016-12-08 11:35:05
【问题描述】:
我遇到了一个有趣的问题。知道ConcurrentDictionary<TKey, TValue> 在被修改时是可以安全枚举的,并且(在我的情况下)迭代可能多次消失或出现的元素会产生不必要的副作用,我决定自己创建一个快照,使用ToList()。由于ConcurrentDictionary<TKey, TValue> 也实现了ICollection<KeyValuePair<TKey, TValue>>,这将导致List(IEnumerable<T> collection) 被使用,这反过来又使用当前项Count 在字典的当前大小中创建一个数组,然后尝试复制项@987654327 @,调用其ConcurrentDictionary<TKey, TValue> 实现,如果同时将元素添加到字典中,则最后抛出ArgumentException。
全部锁定会扼杀使用集合的意义,所以我的选择似乎是要么继续捕获异常并重试(这绝对不是问题的正确答案),要么实现我自己的专门针对此问题的 ToList() 版本(但话又说回来,简单地增长一个列表,然后可能将它修剪到适合一些元素的大小似乎有点过头了,使用 LinkedList 会降低索引性能)。
此外,似乎添加某些在后台创建某种缓冲区的 LINQ 方法(例如OrderBy)似乎确实以牺牲性能为代价来解决问题,但裸露的ToList() 显然可以不是,而且当不需要额外的功能时,不值得用另一种方法“增强”它。
这可能是任何并发收集的问题吗?
在创建此类快照时,将性能影响降至最低的合理解决方法是什么? (最好在一些 LINQ 魔术的结尾。)
编辑:
查看后我可以确认,ToArray()(以为我昨天刚刚路过)确实解决了快照问题,只要它只是一个简单的快照,当附加功能时它没有帮助在拍摄所述快照之前需要(例如过滤,排序),最后仍然需要一个列表/数组。 (在这种情况下,需要额外调用,重新创建新集合。)
我没有指出快照可能需要也可能不需要经过这些修改,因此最好在最后拍摄,所以我会将其添加到问题中。
(另外,如果有人对标题有更好的想法,请告诉。)
【问题讨论】:
-
请改用
.ToArray(),具体由类型实现。
标签: .net linq concurrentdictionary argumentexception