2012-04-16 53 views
21

有没有办法一次添加多个项目到ConcurrentBag,而不是一次一个?我没有看到ConcurrentBag上的AddRange()方法,但有一个Concat()。然而,这不是为我工作:ConcurrentBag - 添加多个项目?

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 <>行之后,objectList始终有0个对象。 Concat <>不是那样工作吗?我需要使用Add()方法一次向ConcurrentBag添加项目吗?

回答

5

是:)

Concat也许是Enumerable扩展之一。它不会向ConcurrentBag添加任何内容,它只是返回一些包含原始包的时髦对象,以及您试图在其中添加的任何内容。

请注意Concat的结果不再是ConcurrentBag,因此您不想使用它。它是通用LINQ框架的一部分,可以组合不可变序列。当然,这个框架不会试图将操作数的并发属性扩展到结果,所以生成的对象不会很适合多线程访问。

(基本上,Concat适用于ConcurrentBag,因为它暴露IEnumerable<T>接口。)

19

Concat是由LINQ提供的扩展方法。这是一个不可变的操作,它返回另一个IEnumerable,它可以枚举紧随指定集合的​​源集合。它不以任何方式更改源集合。

您需要一次将您的物品添加到ConcurrentBag

3

我遇到了一个类似的问题,试图并行处理较小的数据块,因为一个大块超时了我用来访问发送端数据的Web服务,但我不希望事情运行得慢一些通过串行处理每个块。通过记录处理数据记录的速度更慢 - 因为我所调用的服务可以处理批量请求,所以最好在不超时的情况下提交尽可能多的数据。

就像Vlad说的那样,将一个并发包放入一个对象类型列表不会返回一个并发包,所以concat不起作用! (我花了一段时间才意识到我无法做到这一点。)

试试这个,而不是 - 创建一个List<T>,然后创建一个ConcurrentBag<List<T>>。在每个并行迭代中,它将为并发包添加一个新列表。并行循环完成后,循环通过ConcurrentBag和concat(或联合,如果您想消除可能的重复项)到您创建的第一个List<T>,以将所有内容“扁平化”为一个列表。

+0

最后使用SelectMany。 – 2018-02-08 17:06:31

17

(我知道这是一个旧帖子,以为我会添加一些东西)。

像其他人一样说:是的,你需要逐一添加它们。就我而言,我增加了一个小的扩展方法做事情有点清洁,但引擎盖下它做同样的事情:

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)); 
    }