Parallel Foreach Method in C#

Parallel Foreach method in C#

In this article, I am going to discuss the Parallel Foreach Method in C# with some examples.  As we already discussed in our previous article that the Task Parallel Library (TPL) provides two methods (i.e. Parallel.For and Parallel.Foreach) which are conceptually the “for” and “for each” loops, except that, they use multiple threads to execute multiple iterations at the same time on a machine with multiple cores. In our previous article, we already discussed the Parallel for Method in C# with examples. Here, in this article, I am going to keep the focus on Parallel Foreach method.

Parallel.ForEach Method in C#

The Parallel ForEach Method in C# provides a parallel version of the standard, sequential Foreach loop. In standard Foreach loop, each iteration processes a single item from the collection and will process all the items one by one only. However, the Parallel Foreach method executes multiple iterations at the same time on different processors or processor cores. This may open the possibility of synchronization problems. So, the loop is ideally suited to processes where each iteration is independent of the others.

Note: We need to use the parallel loops such as Parallel.For and Parallel.ForEach method to speed up operations where an expensive, independent operation needs to be performed for each input of a sequence.

A sequential Foreach loop in C#:

Standard Foreach Loop in C#

A parallel Foreach loop in C#:

Parallel Foreach Loop in C#

The parallel version of the loop uses the static ForEach method of the Parallel class. There are many overloaded versions available for this method. This is the simplest overloaded version which accepts two arguments. The first one is the collection of objects that will be enumerated. This can be any collection that implements IEnumerable<T>.

The second parameter accepts an Action delegate, usually expressed as a lambda expression which determines the action to take for each item in the collection. The delegate’s parameter contains the item from the collection that is to be processed during the iteration.

Parallel Foreach Method Example.

Let us understand Parallel Foreach with an example. First, we will write an example using the standard sequential Foreach loop and will see how much time it will take to complete the execution. Then we will write the same example using the Parallel ForEach method and will see how much time it will take to complete the execution of the same example.

In the below example, we create a sequential Foreach loop that performs a long-running task once for each item in the collection. The code below loops through a list of ten integers generated using the Enumerable.Range method. In each iteration, the DoSomeIndependentTimeconsumingTask method is called. The DoSomeIndependentTimeconsumingTask method performs a calculation that is included to generate a long enough pause to see the performance improvement of the parallel version.

namespace ParallelProgrammingDemo
{
    class Program
    {
        static void Main()
        {
            DateTime StartDateTime = DateTime.Now;

            Console.WriteLine(@"foreach Loop start at : {0}", StartDateTime);

            List<int> integerList = Enumerable.Range(1, 10).ToList();
            foreach (int i in integerList)
            {
                long total = DoSomeIndependentTimeconsumingTask();
                Console.WriteLine("{0} - {1}", i, total);
            };

            DateTime EndDateTime = DateTime.Now;
            Console.WriteLine(@"foreach Loop end at : {0}", EndDateTime);

            TimeSpan span = EndDateTime - StartDateTime;
            int ms = (int)span.TotalMilliseconds;
            Console.WriteLine(@"Time Taken by foreach Loop in miliseconds {0}", ms);

            Console.WriteLine("Press any key to exist");
            Console.ReadLine();
        }

        static long DoSomeIndependentTimeconsumingTask()
        {
            //Do Some Time Consuming Task here
            //Most Probably some calculation or DB related activity
            long total = 0;
            for (int i = 1; i < 100000000; i++)
            {
                total += i;
            }
            return total;
        }
    }
}

Now run the application and observe the output.

Parallel ForEach Method in C#

As you can see from the above output screen the “Foreach” loop statement took approximately 3035 milliseconds to complete the execution.

Let’s rewrite the same example using the Parallel ForEach method.
namespace ParallelProgrammingDemo
{
    class Program
    {
        static void Main()
        {
            DateTime StartDateTime = DateTime.Now;

            Console.WriteLine(@"Parallel foreach method start at : {0}", StartDateTime);

            List<int> integerList = Enumerable.Range(1, 10).ToList();
            Parallel.ForEach(integerList, i =>
            {
                long total = DoSomeIndependentTimeconsumingTask();
                Console.WriteLine("{0} - {1}", i, total);
            });
            
            DateTime EndDateTime = DateTime.Now;
            Console.WriteLine(@"Parallel foreach method end at : {0}", EndDateTime);

            TimeSpan span = EndDateTime - StartDateTime;
            int ms = (int)span.TotalMilliseconds;
            Console.WriteLine(@"Time Taken by Parallel foreach method in miliseconds {0}", ms);

            Console.WriteLine("Press any key to exist");
            Console.ReadLine();
        }

        static long DoSomeIndependentTimeconsumingTask()
        {
            //Do Some Time Consuming Task here
            //Most Probably some calculation or DB related activity
            long total = 0;
            for (int i = 1; i < 100000000; i++)
            {
                total += i;
            }
            return total;
        }
    }
}

Now, run the application and see the output as shown below. The time may vary on your machine.

Underdtanding Parallel.ForEach Method in C#

As you can see in the above output, the Parallel.ForEach method took 1419 milliseconds to complete the execution.

The Degree of Parallelism:

Using the Degree of Parallelism we can specify the maximum number of threads to be used to execute the program. The syntax to use the Degree of Parallelism is given below.

Degree of Parallelism in Parallel Foreach Method in C#

The MaxDegreeOfParallelism property affects the number of concurrent operations run by Parallel method calls that are passed this ParallelOptions instance. A positive property value limits the number of concurrent operations to the set value. If it is -1, there is no limit on the number of concurrently running operations.

By default, For and ForEach will utilize however many threads the underlying scheduler provides, so changing MaxDegreeOfParallelism from the default only limits how many concurrent tasks will be used.

Let us see an example for better understanding.
namespace ParallelProgrammingDemo
{
    class Program
    {
        static void Main()
        {
            List<int> integerList = Enumerable.Range(0,10).ToList();
            Parallel.ForEach(integerList, i =>
            {
                Console.WriteLine(@"value of i = {0}, thread = {1}",
                    i, Thread.CurrentThread.ManagedThreadId);
            });
            
            Console.WriteLine("Press any key to exist");
            Console.ReadLine();
        }
    }
}

Now run the above code above multiple times, and definitely, you will get different output. You will also observe that the number of threads is created is not in our control. Now, let us see how to restrict the number of threads to be created.

How to control the degree of concurrency i.e. How to restrict the number of threads to be created?

We can restrict the number of concurrent threads created during the execution of parallel loops by using the MaxDegreeOfParallelism property. By assigning some value to MaxDegreeOfParallelism, we can restrict the degree of this concurrency and can restrict the number of processor cores to be used by our loops. The default value of this property is -1, which means there is no restriction on concurrently running operations.

Let’s see the example.

namespace ParallelProgrammingDemo
{
    class Program
    {
        static void Main()
        {
            var options = new ParallelOptions()
            {
                MaxDegreeOfParallelism = 2
            };

            List<int> integerList = Enumerable.Range(0,10).ToList();
            Parallel.ForEach(integerList, options, i =>
            {
                Console.WriteLine(@"value of i = {0}, thread = {1}",
                    i, Thread.CurrentThread.ManagedThreadId);
            });
            
            Console.WriteLine("Press any key to exist");
            Console.ReadLine();
        }
    }
}

In the above code, we are setting the MaxDegreeOfParallelism to 2, which means that only a maximum of 2 threads will be created, that will, in turn, use fewer cores, which is 2 here. Now run the application and see the output as shown below. 

Using MaxDegreeOfParallelism property in C#

Whatever number of times we execute the above code, the number of threads will never go above 2.

In the next article, I am going to discuss the Parallel Invoke Method in C# with some examples. Here, in this article, I try to explain the Parallel ForEach Method with some examples. I hope you understood the need and use of Parallel Foreach method.

Leave a Reply

Your email address will not be published. Required fields are marked *