Parallel Programming In C# To Leverage Multicore Processor

Performance issues

We often find it very difficult to get a solution for performance issues faced in real-world applications.

We use multiple loops to iterate huge amounts of data for processing (e.g. for, foreach, Linq ) queries for the iteration and this results in bad-performing code.

Here is the solution

Microsoft® .NET Framework 4 introduces the Parallel Programming model, which utilizes all the CPU cores and runs your Application code in parallel on all the cores so that you get the fastest computation of your program written in C#.

The normal ( for, foreach, Linq ) iterates in the sequential manner, which means, even if your program is running on a multicore processor, only one core of the processor is used to compute your program.

Hence, basically, you are not getting any benefit from using a multi-core processor.

Below are some examples (with comparisons), which may help you to get all the benefits of running an Application on a multi-core processor machine and get the fastest results.

for vs Parallel.For

When we run the code, given below, we can see the difference.

using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        /***** Normal for Loop ************/
        Console.WriteLine("<=========== Sequential For Loop =============>");
        for (int i = 0; i < 50; i++)
        {
            Console.Write("{0}, ", i);
            await Task.Delay(200);
        }
        Console.WriteLine();

        /******** Parallel For Loop **********/
        Console.WriteLine("<=========== Parallel For Loop ==============>");
        await Task.WhenAll(Parallel.For(0, 50, async i =>
        {
            Console.Write("{0}, ", i);
            await Task.Delay(200);
        }));
        Console.WriteLine();

        Console.ReadLine();
    }
}

Normal “for loop“ prints the results sequentially (It means, only a single core of the CPU is processing the loop) and takes time to complete. Whereas “Parallel.For” printing results non sequentially, which shows the parallel processing of the loop over the multiple cores and producing output much faster than the normal for loop.

output

Parallel.For” takes first input, which is the starting index and then the maximum index (Excluding).

foreach vs Parallel.Foreach

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

public class Person
{
    public string Name { get; set; }
}

class Program
{
    static async Task Main(string[] args)
    {
        var array = new List<Person>
        {
            new Person { Name = "A" },
            new Person { Name = "8" },
            new Person { Name = "C" },
            new Person { Name = "D" },
            new Person { Name = "E" },
            new Person { Name = "F" },
            new Person { Name = "G" },
            new Person { Name = "" },
            new Person { Name = "1" },
            new Person { Name = "3" },
            new Person { Name = "K" },
            new Person { Name = "" },
            new Person { Name = "" },
            new Person { Name = "N" },
            new Person { Name = "0" },
            new Person { Name = "p" }
        };

        Console.WriteLine("< An example with foreach loop >");
        Console.WriteLine("");

        foreach (var p in array)
        {
            Console.Write("({0}), ", p.Name);
            await Task.Delay(200);
        }

        Console.WriteLine("");
        Console.WriteLine("");

        Console.WriteLine("< An example with Parallel foreach loop >");
        await Task.WhenAll(array.ForEachAsync(async p =>
        {
            Console.Write("({0}), ", p.Name);
            await Task.Delay(200);
        }));

        Console.WriteLine("");
        Console.ReadLine();
    }
}

Output

Normal “foreach loop“ prints the results sequentially.

Whereas “Parallel.Foreach” prints the results non sequentially.

output

Linq vs PLinq

Below is the sample code to compare the outputs of the two approaches.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

public class Person
{
    public string Name { get; set; }
}

class Program
{
    static async Task Main(string[] args)
    {
        var array = new List<Person>
        {
            new Person { Name = "A" },
            new Person { Name = "8" },
            new Person { Name = "C" },
            new Person { Name = "D" },
            new Person { Name = "E" },
            new Person { Name = "F" },
            new Person { Name = "G" },
            new Person { Name = "" },
            new Person { Name = "1" },
            new Person { Name = "3" },
            new Person { Name = "K" },
            new Person { Name = "" },
            new Person { Name = "" },
            new Person { Name = "N" },
            new Person { Name = "0" },
            new Person { Name = "p" }
        };

        Console.WriteLine("< Normal LINQ query >");
        Console.WriteLine("***********************");
        array.ForEach(p =>
        {
            Console.Write("({0}), ", p.Name);
            Thread.Sleep(200);
        });
        Console.WriteLine();
        Console.WriteLine();

        Console.WriteLine("< An example with Parallel query PLINQ >");
        Console.WriteLine("***********************");
        array.AsParallel().ForAll(p =>
        {
            Console.Write(".({0}), ", p.Name);
            Thread.Sleep(200);
        });
        Console.WriteLine();

        Console.ReadLine();
    }
}

array.ForEach gives the results sequentially.

array.AsParallel() produces the output in parallel.

output

Making a small change in the way of writing the code can make a huge difference.


Similar Articles