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