Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parallel.For fail (C#)

I wrote some code:

class Program
    {
        public const int count = 3000;
        static List<int> list = new List<int>();
        static void DoWork(int i)
        {            
            list.Add(i);
        }        
        static void Main(string[] args)
        {
            while (true)
            {

                Stopwatch s = new Stopwatch();
                s.Start();
                Parallel.For(0, count + 1, DoWork);            
                s.Stop();
                Console.WriteLine("\n Elapsed: " + s.Elapsed.ToString());
                Console.WriteLine("Expected: {0}", count + 1);
                Console.WriteLine("count: {0}", list.Count);
                Console.ReadKey();
                list = new List<int>(); 
            }
        }
    }

but results are not expected(

Not all of the cycles are finished before Console.WriteLine calls

What is the problem with using Parallel.For?

like image 201
atomohod Avatar asked Jan 20 '23 11:01

atomohod


2 Answers

You're running into what's known as a Race Condition. Since the List collection in .Net isn't thread safe, it's operations such as Add() aren't atomic. Basically a call to Add() on one thread can destroy another thread's Add() before it is complete. You need a thread-safe concurrent collection for your code.

Try this:

using System.Threading.Tasks;
class Program
{

    public const int count = 3000;
    static ConcurrentBag<int> bag = new ConcurrentBag<int>();
    static void DoWork(int i)
    {
        bag.Add(i);
    }
    static void Main(string[] args)
    {
        while (true)
        {

            Stopwatch s = new Stopwatch();
            s.Start();
            Parallel.For(0, count + 1, DoWork);
            s.Stop();
            Console.WriteLine("\n Elapsed: " + s.Elapsed.ToString());
            Console.WriteLine("Expected: {0}", count + 1);
            Console.WriteLine("count: {0}", bag.Count);
            Console.ReadKey();
            bag = new ConcurrentBag<int>();
        }
    }
}

The ConcurrentBag is the closest thing to a thread-safe list. Just remember since we are dealing with unknown scheduling, the integers won't be in order.

like image 71
Alex Moore Avatar answered Jan 27 '23 22:01

Alex Moore


The List<> class is not thread save. You can't modify it in a parallel loop (Without problems). Use a collection form the System.Collections.Concurrent namespace

like image 34
Fox32 Avatar answered Jan 27 '23 23:01

Fox32