Friday, 21 November 2014

Why you should use ConcurrentBag with Parallel Foreach?

namespace ConsoleApp
{
    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;

    class Program
    {
        static void Main(string[] args)
        {
            var targetCount = 10000;
 
            // Shows 7456!
            RunThreadUnsafeDemo(targetCount);

            // Shows 10000
            RunThreadSafeDemo(targetCount);

            Console.ReadKey();
        }

        // The target count is less than actual.
        static void RunThreadUnsafeDemo(int count)
        {
            var sourceList = Enumerable.Range(1, count);
            var targetList = new List();          // Bad idea
            Parallel.ForEach(sourceList, i =>
            {
                targetList.Add(i);
            });

            Console.WriteLine("Thread Unsafe Count: {0}.", targetList.Count);
        }

        // The target count equals to actual.
        static void RunThreadSafeDemo(int count)
        {
            var sourceList = Enumerable.Range(1, count);
            var targetList = new ConcurrentBag(); // Good one
            Parallel.ForEach(sourceList, i =>
            {
                targetList.Add(i);
            });

            Console.WriteLine("Thread Safe Count: {0}.", targetList.Count);
        }
    }
}

No comments: