Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ConcurrentBag - Add Multiple Items?

Is there a way to add multiple items to ConcurrentBag all at once, instead of one at a time? I don't see an AddRange() method on ConcurrentBag, but there is a Concat(). However, that's not working for me:

ConcurrentBag<T> objectList = new ConcurrentBag<T>();  timeChunks.ForEach(timeChunk => {     List<T> newList = Foo.SomeMethod<T>(x => x.SomeReadTime > timeChunk.StartTime);     objectList.Concat<T>(newList); }); 

This code used to be in a Parallel.ForEach(), but I changed it to the above so I could troubleshoot it. The variable newList indeed has objects, but after the objectList.Concat<> line, objectList always has 0 objects in it. Does Concat<> not work that way? Do I need to add items to ConcurrentBag one at a time, with the Add() method?

like image 549
Bob Horn Avatar asked Apr 16 '12 16:04

Bob Horn


People also ask

How do I add a list in ConcurrentBag?

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

What is a concurrent bag?

ConcurrentBag<T> is a thread-safe bag implementation, optimized for scenarios where the same thread will be both producing and consuming data stored in the bag.

How does ConcurrentBag work?

ConcurrentBag allows you to store objects in unordered way. Contrary to ConcurrentDictionary class, it allows you to store duplicate objects. ConcurrentBag allows multiple threads to store the objects. It is optimized for scenarios where same thread act as producer and consumer.


2 Answers

(I know this is an old post, thought I'd add a little something).

Like others have said: yes, you need to add them one by one. In my case, I added a small extension method to make things a bit cleaner, but under the hood it does the same thing:

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

And then:

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

I also looked at using AsParallel to add within the extension method, but after running some tests on adding a list of strings of various sizes, it was consistantly slower to use AsParallel (as shown here) as opposed to the traditional for loop.

    public static void AddRange<T>(this ConcurrentBag<T> @this, IEnumerable<T> toAdd)     {         toAdd.AsParallel().ForAll(t => @this.Add(t));     } 
like image 147
Eric Avatar answered Oct 11 '22 00:10

Eric


Concat is an extension method provided by LINQ. It is an immutable operation that returns another IEnumerable that can enumerate the source collection followed immediately by the specified collection. It does not, in any way, change the source collection.

You will need to add your items to the ConcurrentBag one at a time.

like image 42
Brian Gideon Avatar answered Oct 10 '22 22:10

Brian Gideon