我的情况是这样的:
多个线程必须同时写入同一个集合(add 和 addrange)。物品的顺序不是问题。当所有线程都完成(加入)并回到我的主线程时,我需要以 foreach 样式快速读取所有收集的数据,因为所有线程都已完成,因此不需要实际锁定。
在“过去”中,我可能会在列表上为此使用读写器锁,但是对于新的并发集合,我想知道是否有更好的选择。我只是不知道哪个因为大多数并发集合似乎假设读者也在并发线程上。
我的情况是这样的:
多个线程必须同时写入同一个集合(add 和 addrange)。物品的顺序不是问题。当所有线程都完成(加入)并回到我的主线程时,我需要以 foreach 样式快速读取所有收集的数据,因为所有线程都已完成,因此不需要实际锁定。
在“过去”中,我可能会在列表上为此使用读写器锁,但是对于新的并发集合,我想知道是否有更好的选择。我只是不知道哪个因为大多数并发集合似乎假设读者也在并发线程上。
我不相信你想使用System.Collections.Concurrent
. 这些通常具有额外的开销以允许并发读取。
除非您有很多争用,否则您最好锁定一个简单的List<T>
并添加它。当列表调整大小时,您将有少量开销,但这种情况很少见。
但是,在这种情况下,我可能会做的只是添加到List<T>
每个线程而不是共享线程,然后在处理结束时合并它们,或者简单地迭代每个集合中的所有元素。
您可以在准备好读取时使用 aConcurrentBag
然后调用.ToArray()
or GetEnumerator()
(绕过每次读取的惩罚),但您可能会发现插入速度比您在简单List
. 这实际上取决于争用的数量。ConcurrentBag
分区非常好,但正如您所指出的,它适用于并发读取和写入。
与往常一样,对您的特定情况进行基准测试!多线程性能高度依赖于实际使用中的许多因素,诸如数据类型、插入次数等因素会极大地改变结果 - 少数现实值得一加仑理论。
物品的顺序不是问题。当所有线程都完成(加入)并且我回到我的主线程时,我需要读取所有收集的数据
您根本没有声明对线程安全集合的要求。共享一个集合是没有意义的,因为你从来没有在写作的同时阅读。所有写入都发生在同一个集合上也没关系,因为顺序无关紧要。这也不重要,因为无论如何顺序都是随机的。
所以只需给每个线程自己的集合来填充,不需要锁定。然后一个一个地迭代它们,不需要锁定。
尝试System.Collections.Concurrent.ConcurrentBag
.
从集合的描述:
表示一个线程安全的、无序的对象集合。
我相信这符合您处理多个线程和不重要的项目顺序的标准,稍后当您回到主线程时,您可以快速 foreach 迭代集合并对每个项目采取行动。