How to use Parallel.For and Parallel.ForEach in C#

Victoria D. Doty

Parallelism is the capability to have parallel execution of responsibilities on devices that have a number of cores. Support for parallel programming in .Net was introduced in .Net Framework 4. Parallel programming in .Net enables us to use program resources extra efficiently and with greater programmatic control. This short article talks about how we can get the job done with parallelism in .Net Main programs.

To get the job done with the code illustrations provided in this short article, you should really have Visual Studio 2019 put in in your program. If you don’t now have a copy, you can obtain Visual Studio 2019 below.

Create a .Net Main console software undertaking in Visual Studio

Initially off, let’s build a .Net Main console software undertaking in Visual Studio. Assuming Visual Studio 2019 is put in in your program, stick to the techniques outlined underneath to build a new .Net Main console software undertaking in Visual Studio.

  1. Launch the Visual Studio IDE.
  2. Simply click on “Create new undertaking.”
  3. In the “Create new project” window, select “Console Application (.Net Main)” from the listing of templates shown.
  4. Simply click Up coming.
  5. In the “Configure your new project” window, specify the name and place for the new undertaking.
  6. Simply click Create.

We’ll use this undertaking to illustrate parallel programming in .Net Main in the subsequent sections of this short article.

Concurrency and parallelism in .Net Main

Concurrency and parallelism are two vital concepts in .Net and .Net Main. While they show up to be the same, there are delicate discrepancies between them.

Look at two responsibilities, T1 and T2, that have to be executed by an software. These two responsibilities are in concurrent execution if 1 is in an execution state although the other is waiting for its switch. As a end result, 1 of the responsibilities completes in advance of the other. By distinction, the two responsibilities are in parallel execution if both of those execute simultaneously. To obtain job parallelism, the program must run on a CPU with a number of cores.

Parallel.For and Parallel.ForEach in .Net Main

The Parallel.For loop executes iterations that may possibly run in parallel. You can keep track of and even manipulate the state of the loop. The Parallel.For loop is just like the for loop besides it enables the iterations to run in parallel throughout a number of threads.

The Parallel.ForEach approach splits the get the job done to be carried out into a number of responsibilities, 1 for each individual product in the selection. Parallel.ForEach is like the foreach loop in C#, besides the foreach loop runs on a one thread and processing acquire area sequentially, although the Parallel.ForEach loop runs on a number of threads and the processing normally takes area in a parallel manner.

Parallel.ForEach vs. foreach in C#

Look at the adhering to approach that accepts an integer as parameter and returns accurate if it is a primary quantity.

static bool IsPrime(int integer)
       
            if (integer <= 1) return false
            if (integer == 2) return accurate
            var restrict = Math.Ceiling(Math.Sqrt(integer))
            for (int i = 2 i <= limit ++i)
                if (integer {394cb916d3e8c50723a7ff83328825b5c7d74cb046532de54bc18278d633572f} i == )
                    return phony
            return accurate
       

We’ll now acquire edge of ConcurrentDictionary to keep the primary quantities and managed thread Ids. Considering that the primary quantities between two ranges are exclusive, we can use them as keys and the managed thread Ids as values.

Concurrent collections in .Net are contained inside the System.Collections.Concurrent namespace and deliver lock-free and thread-safe implementations of the selection courses. The ConcurrentDictionary course is contained inside the System.Collections.Concurrent namespace and represents a thread-safe dictionary.

The adhering to two techniques both of those use the IsPrime approach to check if an integer is a primary quantity, keep the primary quantities and managed thread Ids in an occasion of a ConcurrentDictionary, and then return the occasion. The very first approach employs concurrency and the second approach employs parallelism.

        private static ConcurrentDictionary
        GetPrimeNumbersConcurrent(IList quantities)
       
            var primes = new ConcurrentDictionary()
            foreach (var quantity in quantities)
                           
                if(IsPrime(quantity))
               
                    primes.TryAdd(quantity,
                    Thread.CurrentThread.ManagedThreadId)
               
           
            return primes
       
        private static ConcurrentDictionary
        GetPrimeNumbersParallel(IList quantities)
       
            var primes = new ConcurrentDictionary()
            Parallel.ForEach(quantities, quantity =>
           
                if (IsPrime(quantity))
               
                    primes.TryAdd(quantity,
                    Thread.CurrentThread.ManagedThreadId)
               
            )
            return primes
       

Concurrent vs. parallel case in point in C#

The adhering to code snippet illustrates how you can invoke the GetPrimeNumbersConcurrent approach to retrieve all primary quantities between 1 to one hundred as well as the managed thread Ids.

static void Major(string[] args)
       
            var quantities = Enumerable.Range(, one hundred).ToList()
            var end result = GetPrimeNumbersConcurrent(quantities)
            foreach(var quantity in end result)
           
                Console.WriteLine($"Primary Number:
                string.Format(":0000",quantity.Key),
                Managed Thread Id: quantity.Worth")
           
            Console.Read through()
       

When you execute the above program, you should really see the output as shown in Figure 1:

parallelforeach in csharp 01 IDG

Figure 1.

As you can see, the managed thread Id is the same in each individual circumstance given that we used concurrency in this case in point. Let’s now see what the output would search like when employing thread parallelism. The adhering to code snippet illustrates how you can retrieve primary quantities between 1 to one hundred employing parallelism.

        static void Major(string[] args)
       
            var quantities = Enumerable.Range(, one hundred).ToList()
            var end result = GetPrimeNumbersParallel(quantities)
            foreach(var quantity in end result)
           
                Console.WriteLine($"Primary Number:
                string.Format(":0000",quantity.Key),
                Managed Thread Id: quantity.Worth")
           
            Console.Read through()
       

When you execute the above program, the output should really search a little something like that shown in Figure 2:

parallelforeach in csharp 02 IDG`

Figure 2.

As you can see below, due to the fact we have used Parallel.ForEach, a number of threads have been established and therefore the managed thread Ids are dissimilar.

Limit the degree of parallelism in C#

The degree of parallelism is an unsigned integer quantity that denotes the maximum quantity of processors that your question should really acquire edge of although it is in execution. In other words and phrases, the degree of parallelism is an integer that denotes the maximum quantity of responsibilities that will be executed at the same point in time to method a question.

By default, the Parallel.For and Parallel.ForEach techniques have no restrict on the quantity of spawned responsibilities. So, in the GetPrimeNumbersParallel approach shown above, the program makes an attempt to use all of the out there threads in the program.

You can acquire edge of the MaxDegreeOfParallelism property to restrict the quantity of spawned responsibilities (per ParallelOptions occasion of the Parallel course). If MaxDegreeOfParallelism is set to -1, then there is no restrict on the quantity of concurrently jogging responsibilities.

The adhering to code snippet demonstrates how you can set MaxDegreeOfParallelism to use a maximum of 75{394cb916d3e8c50723a7ff83328825b5c7d74cb046532de54bc18278d633572f} resources of the program.

new ParallelOptions

    MaxDegreeOfParallelism = Transform.ToInt32(Math.Ceiling((Atmosphere.ProcessorCount * .75) * 2.))

Note that in the above snippet we have multiplied the processor count by two due to the fact each individual processor has two cores. Right here is the total current code of the GetPrimeNumbersParallel approach for your reference:

        private static ConcurrentDictionary GetPrimeNumbersParallel(IList quantities)
       
            var primes = new ConcurrentDictionary()
            Parallel.ForEach(quantities, quantity =>
           
                new ParallelOptions
               
                    MaxDegreeOfParallelism = Transform.ToInt32(Math.Ceiling((Atmosphere.ProcessorCount * .75) * 2.))
               
                if (IsPrime(quantity))
               
                    primes.TryAdd(quantity,
                    Thread.CurrentThread.ManagedThreadId)
               
            )
            return primes
       

Figure out if a parallel loop is total in C#

Note that both of those Parallel.For and Parallel.ForEach return an occasion of ParallelLoopResult, which can be used to establish if a parallel loop has accomplished execution. The adhering to code snippet demonstrates how ParallelLoopResult can be used.

ParallelLoopResult parallelLoopResult = Parallel.ForEach(quantities, quantity =>
 
    new ParallelOptions
   
          MaxDegreeOfParallelism = Transform.ToInt32(Math.Ceiling(
          (Atmosphere.ProcessorCount * .75) * 2.))
   
    if (IsPrime(quantity))
   
          primes.TryAdd(quantity, Thread.CurrentThread.ManagedThreadId)
   
 )
Console.WriteLine("IsCompleted: ", parallelLoopResult.IsCompleted)

To use Parallel.ForEach in a non-generic selection, you should really acquire edge of the Enumerable.Forged extension approach to change the selection to a generic selection as illustrated in the code snippet specified underneath.

Parallel.ForEach(nonGenericCollection.Forged(),
    currentElement =>
   
    )

On a last notice, don’t believe that the iterations of Parallel.For or Parallel.ForEach will always execute in parallel. You should really also be informed of thread affinity troubles. You can read about these and other likely pitfalls in job parallelism in Microsoft’s on line documentation below.

How to do extra in C#:

Copyright © 2021 IDG Communications, Inc.

Next Post

No one wants to manage Kubernetes anymore

Controlling Kubernetes is tough, and numerous businesses are starting to comprehend they can improved concentrate on other, as-nevertheless unsolved engineering complications if they hand off a big chunk of their container orchestration obligations to managed assistance suppliers. Now, the most common managed Kubernetes options—sometimes referred to as Kubernetes as a […]

Subscribe US Now