Home > Blockchain >  Most efficient way to enumerate and modify over a ConcurrentBag of objects
Most efficient way to enumerate and modify over a ConcurrentBag of objects

Time:12-15

I have a ConcurrentBag of objects, and I want to do following over it:

  1. enumerate all items with a where filtering.
  2. for each item, check some properties, and based on the values, make some method call. After the method call, it's better to remove the item form the bag.
  3. modify some properties' value and save it to the bag.

So basically I need something like following:

   foreach (var item in myBag.Where(it => it.Property1 = true))
        {
            
            if (item.Property2 = true)
            {
                SomeMethodToReadTheItem(item);
                //it's better to remove this item from the bag here, but 
                //there is a permeance hit, then just leave it.
            }
            else
            {
                item.Property3=  "new value";
                //now how do I save the item back to the bag?
            }
            
        }

Of cause it should be done in a thread-safe way. I know that the enumeration over a ConcurrentBag is actually over a "snapshot" of the real bag, but how about with a where clause filter? Should I do a ToList to prevent it form making a new "snapshot"? Also if you want to modify one specific item, you just bag.TryTake(out item). But since I've already get the item in the enumeration, should I "take" it again?

Any explanation/comment/sample would be very much apricated.

Thank you.

CodePudding user response:

I recommend you just create a new list and, if the WHERE filter, add it to this new list. It would look something like this:

List<T> myNewList = new List<T>();
foreach (var item in myBag.Where(it => it.Property1 = true))
    {
        if (!item.Property2 = true)
        {
            myNewList.Add(item);
        }            
    }

attention to " ! "

CodePudding user response:

I'll try to answer specific parts of your question without addressing the performance.

First off, the Where method takes an IEnumerable<T> as its first parameter and will itself iterate over the enumerable which will call GetEnumerator() once so you will only take one snapshot of the underlying ConcurrentBag.

Secondly the thread-safety of your code is not very clear, there may be some implicit guarantees in the rest of your code which are not specified. For example you have a ConcurrentBag so your collection is thread-safe however you modify the items contained within that collection without any thread synchronisation. If there is other code that runs the same method or in another method that reads/modifies the items in the ConcurrentBag concurrently then you may see data races.

Note that it is not necessary to call TryTake if you already have a reference to the item as it will only return the same reference.

  • Related