定期迭代不断变化的集合
我有一个不断变化的对象集合,我想经常显示一些有关内容的信息(我的应用程序是多线程的,不同的线程不断提交修改集合中对象的请求,因此它是不可预测的) 。
如果我锁定集合,我可以迭代它并获取我的信息,不会出现任何问题 - 但是,这会导致其他线程出现问题,因为它们可能同时提交了多个请求来修改集合,并且将被停止。我已经想到了几种解决这个问题的方法,并且正在寻求任何建议。
- 制作集合的副本并对其进行迭代,从而允许原始集合在后台继续更新。该集合可能会变得很大,因此这并不理想,但很安全。
- 使用 For...Next 循环对其进行迭代,如果在迭代时从集合中删除了某个项目,则捕获 IndexOutOfBounds 异常。这有时可能会导致我的快照中出现重复项,因此这也不理想。
还有其他想法吗?我只关心即时快照,因此我不关心反映应用程序中的更改 - 我主要关心的是集合能够以最小的延迟进行更新,并且更新永远不会丢失。
I have a collection of objects that's constantly changing, and I want to display some information about the contents every so often (my application is multi-threaded, and differently threads are constantly submitting requests to modify an object in the collection, so it's unpredictable).
If I lock the collection, I can iterate over it and get my information without any problems - however, this causes problems with the other threads, since they could have submitted multiple requests to modify the collection in the meantime, and will be stalled. I've thought of a couple ways around this, and I'm looking for any advice.
- Make a copy of the collection and iterate over it, allowing the original to continue updating in the background. The collection can get large, so this isn't ideal, but it's safe.
- Iterate over it using a For...Next loop, and catch an IndexOutOfBounds exception if an item is removed from the collection while we're iterating. This may occasionally cause duplicates to appear in my snapshot, so it's not ideal either.
Any other ideas? I'm only concerned about a moment-in-time snapshot, so I'm not concerned about reflecting changes in my application - my main concern is that the collection be able to be updated with minimal latency, and that updates never be lost.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您使用的是 .NET Framework 4,您可能需要考虑使用
System.Concurrent
命名空间中的一些并发集合。例如,从ConcurrentQueue
类返回的迭代器表示集合的即时视图,并且不受集合中更改的影响。 普通集合迭代器将因底层集合的更改而失效。否则,你别无选择,只能先锁定集合。也许有并发集合的第三方实现。但我还没有研究过这些。以下是有关 .NET Framework 4 中线程安全集合的信息。http://msdn.microsoft.com/en-us/library/dd997305(v=VS.100).aspx
You might want to look into using some concurrent collections from
System.Concurrent
namespace, if you are using .NET Framework 4. For example iterators returned from theConcurrentQueue<T>
class represent a moment-in-time view of the collection and are not affected by change in the collection. Normal collection iterators will be invalidated by changes in the underlying collection. Otherwise, you have no choice, but to lock the collection first. Maybe there are third-party implementations of concurrent collections. But I have not looked into those. Here is information on thread-safe collections in .NET Framework 4.http://msdn.microsoft.com/en-us/library/dd997305(v=VS.100).aspx
我倾向于使用您的第一个选项,使用 .ToArray() 创建一个数组并对其进行迭代。您是否对其进行了分析以了解其复制速度有多慢?它通常对我来说可以忽略不计,即使对于大型收藏也是如此。
I tend to use your first option, making an array with .ToArray() and iterating over that. Have you profiled it to see how slow it is making a copy? It's usually been negligible for me, even for large collections.
制作集合的副本通常需要您首先锁定集合,因此与仅锁定它并迭代它相比,这里没有任何好处 - 除非您的集合支持某种快速克隆。
我认为另一种选择是使用不同类型的集合,这些集合可以更好地支持并发访问,或者能够快速返回快照。这里的另一个答案链接到 .net 特定的答案;如果您有兴趣自己实现一个,我建议您阅读这篇论文:
http://www.cs.tau.ac.il/~shanir/concurrent-data-structs.pdf
Making a copy of the collection typically requires you to lock the collection first, so no gain here compared with just locking it and iterating over it - unless your collection supports some sort of fast cloning.
I think an alternative can be to use different kinds of collections, ones that have better support for concurrent accesses, or an ability to return snapshots quickly. Another answer here linked to .net specific ones; if you're interested in implementing one yourself I would suggest this paper:
http://www.cs.tau.ac.il/~shanir/concurrent-data-structures.pdf