有没有办法一次向ConcurrentBag添加多个项目,而不是一次添加一个?我没有在ConcurrentBag上看到AddRange()方法,但是有一个Concat()。但是,这对我不起作用:
ConcurrentBag<T> objectList = new ConcurrentBag<T>();
timeChunks.ForEach(timeChunk =>
{
List<T> newList = Foo.SomeMethod<T>(x => x.SomeReadTime > timeChunk.StartTime);
objectList.Concat<T>(newList);
});
这段代码曾经在Parallel.ForEach()中,但是我把它改成了上面所以我可以解决它。变量newList确实具有对象,但是在objectList.Concat&lt;&gt;之后。 line,objectList总是有0个对象。 Concat&lt;&gt;不这样做?我是否需要使用Add()方法一次一个地向ConcurrentBag添加项目?
答案 0 :(得分:24)
(我知道这是一篇很老的帖子,以为我会添加一些东西)。
像其他人一样说:是的,你需要逐个添加它们。在我的情况下,我添加了一个小的扩展方法,使事情更清洁,但在幕后它做同样的事情:
public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd)
{
foreach (var element in toAdd)
{
@this.Add(element);
}
}
然后:
ConcurrentBag<int> ccBag = new ConcurrentBag<int>();
var listOfThings = new List<int>() { 1, 2, 4, 5, 6, 7, 8, 9 };
ccBag.AddRange(listOfThings);
我还考虑使用AsParallel在扩展方法中添加,但是在添加各种大小的字符串列表运行一些测试之后,使用AsParallel(如此处所示)与传统的for循环相比,速度慢得多
public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd)
{
toAdd.AsParallel().ForAll(t => @this.Add(t));
}
答案 1 :(得分:19)
Concat
是LINQ提供的扩展方法。这是一个不可变的操作,它返回另一个IEnumerable
,它可以枚举源集合,紧接着是指定的集合。它不会以任何方式更改源集合。
您需要一次将商品添加到ConcurrentBag
。
答案 2 :(得分:6)
是的:)
Concat
可能是Enumerable
个扩展之一。它不会向ConcurrentBag
添加任何内容,只会返回一些包含原始包的时髦对象以及您尝试添加的任何内容。
请注意Concat
的结果不再是ConcurrentBag
,因此您不想使用它。它是一般LINQ框架的一部分,可以组合不可变序列。当然,这个框架不会尝试将操作数的并发属性扩展到结果,因此生成的对象不太适合多线程访问。
(基本上,Concat
适用于ConcurrentBag
,因为它会公开IEnumerable<T>
接口。)
答案 3 :(得分:6)
我遇到了类似的问题,尝试并行处理较小的数据块,因为一个大块超时我用来访问发送端数据的Web服务,但我不想让事情变慢连续处理每个块。按记录处理数据记录的速度甚至更慢 - 因为我调用的服务可以处理批量请求,所以最好尽可能多地提交,而不会超时。
像Vlad说的那样,将并发包连接到对象类型列表不会返回并发包,因此concat将无效! (我花了一段时间才意识到我无法做到这一点。)请尝试此操作 - 创建List<T>
,然后创建ConcurrentBag<List<T>>
。在每次并行迭代中,它将向并发包添加新列表。完成并行循环后,循环遍历ConcurrentBag
和concat(或者如果要消除可能重复的联合)到您创建的第一个List<T>
以将所有内容“展平”到一个列表中。
答案 4 :(得分:0)
Concat
方法是公共 Enumerable
静态类中包含的一种方法,该静态类支持 System.Linq
库(内部 .NET System.Core
程序集)。
但是,Concat
包含向ConcurrentBag<T>
对象提供“添加范围”要求的限制,其行为如下图所示(在Visual Studio中的第47行):
要使Concat
方法符合“添加范围”的要求,必须更新当前的ConcurrentBag<T>
对象实例;如果程序需要添加多个范围,则有必要针对每个范围从当前ConcurrentBag<T>
(递归)创建自动引用实例。
然后,我不使用Concat
方法,如果可以提出建议,则不推荐。我从Eric的答案中得到一个类似的例子,在该案例中,我从ConcurrentBag<T>
开发了一个派生类,该类向我提供了AddRange方法,该方法使用了ConcurrentBag<T>
基本方法来添加IEnumerable<T>
项到派生实例,如下所示:
public class ConcurrentBagCompleted<T> : ConcurrentBag<T> { public ConcurrentBagCompleted() : base() { } public ConcurrentBagCompleted(IEnumerable<T> collection):base(collection) { } public void AddRange(IEnumerable<T> collection) { Parallel.ForEach(collection, item => { base.Add(item); }); } }