我可以在 ConcurrentBag 上使用普通的 foreach 吗?

Posted

技术标签:

【中文标题】我可以在 ConcurrentBag 上使用普通的 foreach 吗?【英文标题】:Can I use a normal foreach on a ConcurrentBag? 【发布时间】:2016-05-17 18:08:18 【问题描述】:

在我的代码的并行部分中,我将每个线程的结果保存到 ConcurrentBag。但是,当这完成后,我需要遍历每个结果并通过我的评估算法运行它们。正常的 foreach 会真正遍历所有成员,还是需要特殊代码?我也考虑过使用队列而不是袋子之类的东西,但我不知道哪个最好。在并行代码的末尾,袋子通常只包含 20 件左右的物品。

即,实际上会为 ConcurrentBag 的所有成员访问并运行 foreach 吗?

ConcurrentBag futures = new ConcurrentBag();
foreach(move in futures)

 // stuff

【问题讨论】:

因为它是 IEnumerable 你应该能够在 ConcurrentBag 上使用 foreach 我添加了示例代码。我问是因为使用 ConcurrentBag 无法保证您的物品以任何特定顺序出现。 我还需要查看填充此并发包的代码......并且并发包已经由线程填充?或者您打算在其他线程仍在更新 ConcurrentBag 时执行 foreach? 并发包在填充后会被查看。此时只有一个线程会触及它。 【参考方案1】:

你不需要特殊代码,C#的foreach会调用“GetEnumerator”which gives you a snapshot:

列举的项目代表一个瞬间的快照 包的内容。它不反映对集合的任何更新 在调用 GetEnumerator 之后。

【讨论】:

【参考方案2】:

您可以在 ConcurrentBag 上使用普通 ForEach,但不会对性能产生任何影响。

这类似于在 List 上使用 ForEach。

为了获得更好的性能,请在 ConcurrentBag 上使用 Parallel.Foreach。

Parallel.ForEach(futures,move=> doOperation;);

仅当您想要执行多线程操作时才使用 ConcurrentBag。

【讨论】:

Parallel.ForEach() 不会神奇地为您提供更好的性能。在相当常见的情况下,Parallel.ForEach() 实际上比foreach 慢得多。 Parallel.ForEach 如果你使用大数据会很快 我想阅读一些关于此的文档。现在,我将尝试一个普通的 foreach,因为快照在我更简单的用例中已经足够好了。

以上是关于我可以在 ConcurrentBag 上使用普通的 foreach 吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何避免 ConcurrentBag<T>.GetEnumerator() 上的争用

Parallel.For 和 ConcurrentBag 给出不可预测的行为

C#ConcurrentBag - 如何安全地清除每个添加的N个对象

C# ConcurrentBag与list

为啥 ConcurrentBag<T> 在 .Net (4.0) 中这么慢?我做错了吗?

线程安全ConcurrentBag