ConcurrentBag - 添加多个项目?

时间:2012-04-16 16:12:41

标签: c# concurrency concurrent-collections

有没有办法一次向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添加项目?

5 个答案:

答案 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行):

enter image description here

要使Concat方法符合“添加范围”的要求,必须更新当前的ConcurrentBag<T>对象实例;如果程序需要添加多个范围,则有必要针对每个范围从当前ConcurrentBag<T>(递归)创建自动引用实例。

enter image description here

然后,我不使用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);
        });
    }
}