ConcurrentBag - 添加多个项目?

Bob*_*orn 35 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);
});
Run Code Online (Sandbox Code Playgroud)

这段代码曾经在Parallel.ForEach()中,但我把它改成了上面所以我可以解决它.变量newList确实有对象,但是在objectList.Concat <>行之后,objectList总是有0个对象.Concat <>不能那样工作吗?我是否需要使用Add()方法一次一个地向ConcurrentBag添加项目?

小智 35

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

像其他人一样说:是的,你需要逐个添加它们.在我的情况下,我添加了一个小的扩展方法,使事情更清洁,但在引擎盖下它做同样的事情:

    public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd)
    {
        foreach (var element in toAdd)
        {
            @this.Add(element);
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后:

    ConcurrentBag<int> ccBag = new ConcurrentBag<int>();
    var listOfThings = new List<int>() { 1, 2, 4, 5, 6, 7, 8, 9 };
    ccBag.AddRange(listOfThings);
Run Code Online (Sandbox Code Playgroud)

我还看了使用AsParallel在扩展方法中添加,但是在添加各种大小的字符串列表运行一些测试之后,使用AsParallel(如此处所示)与传统的for循环相比,速度慢得多.

    public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd)
    {
        toAdd.AsParallel().ForAll(t => @this.Add(t));
    }
Run Code Online (Sandbox Code Playgroud)


Bri*_*eon 19

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

您需要一次添加ConcurrentBag一个项目.


小智 6

我遇到了类似的问题,试图并行处理较小的数据块,因为一个大块超时我用来访问发送端数据的Web服务,但我不希望通过处理每个块来减慢运行速度连续.按记录处理数据记录甚至更慢 - 因为我调用的服务可以处理批量请求,所以最好尽可能多地提交而不超时.

就像弗拉德说的那样,将一个并发包连接到一个对象类型的列表不会返回一个并发包,所以concat将不起作用!(我花了一段时间才意识到我做不到.)

试试这个 - 创建一个List<T>,然后创建一个ConcurrentBag<List<T>>.在每次并行迭代中,它将向并发包添加新列表.完成并行循环后,循环遍历ConcurrentBag和concat(或者如果要消除可能的重复项,则为union)到List<T>您创建的第一个"将所有内容""展平"到一个列表中.

  • 最后要扁平化使用 SelectMany。 (2认同)

Vla*_*lad 5

是的:)

Concat也许是其中一个Enumerable扩展.它没有添加任何内容ConcurrentBag,只是返回一些包含原始包的时髦对象以及您尝试添加的任何内容.

要注意的是结果Concat不是ConcurrentBag了,所以你不希望使用它.它是一般LINQ框架的一部分,可以组合不可变序列.当然,这个框架不会尝试将操作数的并发属性扩展到结果,因此生成的对象不太适合多线程访问.

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

  • 这个“答案”显然没有回答问题。不知道为什么它被标记为答案。 (2认同)