Is Parallel.ForEach in ConcurrentBag<T> thread safe

10,623

That looks fine to me. The way you're using it is thread-safe.

If you could return an IEnumerable<XYZ>, it could be made more efficient by not copying to a List<T> when you're done.

Share:
10,623

Related videos on Youtube

Vlad Bezden
Author by

Vlad Bezden

Software engineer with more than 30 years of experience. I specialized in developing highly scalable and high-performance systems. Polyglot: JavaScript, Python, Java, Go, Java, C, C++, C#.

Updated on October 23, 2020

Comments

  • Vlad Bezden
    Vlad Bezden over 3 years

    Description of ConcurrentBag on MSDN is not clear:

    Bags are useful for storing objects when ordering doesn't matter, and unlike sets, bags support duplicates. ConcurrentBag is a thread-safe bag implementation, optimized for scenarios where the same thread will be both producing and consuming data stored in the bag.

    My question is it thread safe and if this is a good practice to use ConcurrentBag in Parallel.ForEach.

    For Instance:

        private List<XYZ> MyMethod(List<MyData> myData)
        {
            var data = new ConcurrentBag<XYZ>();
    
            Parallel.ForEach(myData, item =>
                            {
                                // Some data manipulation
    
                                data.Add(new XYZ(/* constructor parameters */);
                            });
    
            return data.ToList();
        }
    

    This way I don't have to use synchronization locking in Parallel.ForEach using regular List.

    Thanks a lot.

  • Sprague
    Sprague almost 11 years
    Does this actually offer any improvement in performance? Won't the .Add function synchronize in order to be thread-safe? (assuming that the code commented out takes 0ms to complete.)
  • Stephen Cleary
    Stephen Cleary almost 11 years
    The concurrent collections use a mixture of lock-free and partial locking techniques. They do not lock the entire collection for every operation.
  • Sprague
    Sprague almost 11 years
    Thanks for clarifying. For those interested, I actually ran a benchmark of this and also decompiled the CLR code. It uses Interlocked.Exchange and Monitor.Enter. I suppose this is what you're referring to as partial locking? At any rate, the parallel code ran faster almost every time, only for very low iteration amounts and small delays did the 'vanilla' way improve performance. I'm not sure I would use this technique myself (don't forget the code commented out needs to be thread-safe!), but it is fast.