Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/314.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用ConcurrentBag类型作为列表的线程安全替代品_C#_Collections - Fatal编程技术网

C# 使用ConcurrentBag类型作为列表的线程安全替代品

C# 使用ConcurrentBag类型作为列表的线程安全替代品,c#,collections,C#,Collections,一般来说,使用ConcurrentBag类型是否可以作为列表的线程安全替代品?我在这里读到了一些答案,建议在C#中的泛型列表出现线程安全问题时使用ConcurrentBag 然而,在阅读了一点有关ConcurrentBag的内容后,它似乎执行了大量搜索并在集合中循环,这与它的预期用途不符。这似乎主要是为了解决生产者/消费者的问题,即工作岗位(有些是随机的)被添加和删除 这是我希望与ConcurrentBag一起使用的(IEnumerable)操作类型的一个示例: ... private read

一般来说,使用
ConcurrentBag
类型是否可以作为
列表的线程安全替代品?我在这里读到了一些答案,建议在C#中的泛型列表出现线程安全问题时使用
ConcurrentBag

然而,在阅读了一点有关ConcurrentBag的内容后,它似乎执行了大量搜索并在集合中循环,这与它的预期用途不符。这似乎主要是为了解决生产者/消费者的问题,即工作岗位(有些是随机的)被添加和删除

这是我希望与
ConcurrentBag
一起使用的(
IEnumerable
)操作类型的一个示例:

...
private readonly ConcurrentBag<Person> people = new ConcurrentBag<Person>();

public void AddPerson(Person person)
{
   people.Add(person);
}

public Person GetPersonWithName(string name)
{
   return people.Where(x => name.Equals(x.Name)).FirstOrDefault();
}
...
。。。
private readonly ConcurrentBag people=新ConcurrentBag();
公众人士(人)
{
人。添加(人);
}
公共人物GetPersonWithName(字符串名称)
{
返回people.Where(x=>name.Equals(x.name)).FirstOrDefault();
}
...

这会导致性能问题吗?使用
ConcurrentBag
收集是否是正确的方法?

收集是最普遍的收集形式,允许多个相同的条目,甚至不需要对列表进行排序。它在生产者/消费者环境中确实很有用,在生产者/消费者环境中,公平性不是一个问题,但它不是专门为此设计的


因为袋子的内容没有任何结构,所以它不太适合执行搜索。特别是,您提到的用例将需要与包的大小成比例的时间。如果您不需要存储项目的多个副本,并且您的用例可以接受手动同步,则哈希集可能会更好。

据我所知,ConcurrentBag使用多个列表。它使用ConcurrentBag为每个线程创建一个列表。因此,当再次在同一线程内读取或访问ConcurrentBag时,性能应与仅使用普通列表时大致相同,但如果从不同线程访问ConcurrentBag,则会产生性能开销,因为它必须在为每个线程创建的“内部”列表中搜索值

MSDN页面说明了以下关于ConcurrentBag的内容

当顺序无关紧要时,袋子对于存储对象很有用,而且与集合不同,袋子支持重复。ConcurrentBag是一个线程安全的包实现,针对同一线程同时生成和使用包中存储的数据的场景进行了优化


.NET内置的并发数据结构最适合于生产者-消费者这样的模式,在这种模式中,通过容器的工作流是恒定的

在您的例子中,列表似乎是长期(相对于类的生命周期)存储,而不仅仅是在消费者将数据带走并对其进行处理之前,一些数据的休息场所。在这种情况下,我建议使用普通的
列表
(或最适合您打算执行的操作的非并发集合),并简单地使用
来控制对它的访问

一般来说,使用ConcurrentBag类型是否可以作为列表的线程安全替代品

不,一般来说不是这样,因为与沃伦·德鲁的观点一致,一份清单是有序的,而一个袋子不是(我的肯定不是;)

但是,如果(潜在并发)读操作的数量远远超过写操作的数量,那么您可以直接使用

这是一个通用的解决方案,因为您使用的是原始列表实例,除了(如上面链接中更详细地解释的)您必须确保每个修改列表的人都使用适当的“写时复制”实用程序方法之外,您可以通过使用来强制执行该方法


在高度并发的程序中,与锁定相比,写时拷贝在大多数读取场景中具有许多理想的性能属性。

@terrybozzio在本例中,4。我想我遇到了一个事实,即在4.5中实例化ConcurrentBags时修复了4中的性能问题。在这种情况下,只有一个ConcurrentBag被实例化为singleton。不过,我最关心的是使用ConcurrentBag替代列表的理论。如果顺序很重要,
ConcurrentBag
并不能很好地替代
List
。根据添加项目的线程,线程将以不同的顺序删除项目。有关这方面的更多信息,请参阅。@JimMischel感谢提供有用的链接。您的博客也证实了我的怀疑,即ConcurrentBag似乎是用于纯生产者/消费者应用程序的。这似乎表明它并非真正用于在集合中搜索/删除特定项的操作,换句话说,列出通常属于时间N的操作。但是,在这些情况下,顺序并不重要,使用了搜索/删除特定项目的功能。请特别注意,如果您的after IEnumberable+Add why not ConcurrentQueue?
HashSet
不是线程安全的。为了线程安全,最好使用
ConcurrentDictionary
。@Norfolc这就是我提到手动同步的原因。ConcurrentDictionary也可能是一个选项。这个问题提到了很多搜索,对于这些搜索,列表可能不是最优的。@WarrenDew谢谢,我添加了一个注释