Monday, November 28, 2016

Parallel.For and Parallel.Foreach – Task Parallel Library


Task Parallel Library provides Parallel.For and Parallel.Foreach methods to achieve data parallelism. Data parallelism refers to scenario where you can perform operation in parallel. The Parallel.For and Parallel.foreach methods are part of System.Threading.Tasks.Parallel.

Sequential loop like below -

for(int i=0; i<10; i++)
     Console.Write("{0},",i);

Output -
0,1,2,3,4,5,6,7,8,9,


Parallel for loop –

Parallel.For(0, 10, i => Console.Write("{0},",i));

Output –
2,3,4,8,9,1,7,6,5,0,


Parallel foreach loop - 

List<int> numbers = new List<int>() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Parallel.ForEach(numbers, x => Console.Write("{0},", x));

Output –
2,3,5,7,9,1,8,4,6,0,

As we all know about how sequential loop works. But when parallel loop executes, the task parallel library partitioned data into multiple parts and loop can iterate on multiple parts concurrently. Internally task scheduler of TPL partitioned data and distribute data between multiple threads if required. So you can see the output of parallel for loop is different than sequential for loop. With parallel loop, order of data is not guaranteed because task parallel library divides data in multiple parts and process it in parallel.

Parallel For and Foreach loops gives you best performance via utilizing the multiple cores of your machine. Developer can use parallel loops to leverage full potential of the available hardware. Task parallel Library internally manages code to adjust with different cores and hardware without changing it. If you running parallel loops with single core machine this will use single core to run parallel loops and takes bit more time compare to run the same on four core machine. See below image where parallel loop utilizes four cores of your machine equally to complete its operation.





How to break parallel loops in between?


We normally break sequential loops using break keyword like below.

for (int i = 0; i < 500; i++)
{
    if (i == 100)
        break;
    Console.Write("{0},", i);
}

But you can’t use break with Parallel loops. There is different way to break parallel loop on some condition. If you want to break parallel loop, then you need to use different overload methods of Parallel for and foreach where delegate accepts ParallelLoopState like below.

public static ParallelLoopResult For(int fromInclusive, int toExclusive, Action<int, ParallelLoopState> body);

See below example to break parallel loops -

Parallel.For(0, 10, (int i, ParallelLoopState loopstate) =>
{
    if (i == 5)
    {
       loopstate.Break();
return;
    }

    Console.Write("{0},", i);
});

Output –
8,4,2,6,3,0,1,

As you can see in output when variable ‘i’ value is 5, loop will break. But in parallel loops the order is not guaranteed because task parallel library divides data in multiple parts and run concurrently.

If you break loop in between means loop is not completed fully. You can check status whether loop is completed or not using ParallelLoopResult. ParallelLoopResult is return type for almost all Paralle.For and Parallel.Foreach overload methods. ParallelLoopResult can also be used to know the value of LowestBreakIteration (loop break value). See below example to check whether loop is completed or not or break in between.

ParallelLoopResult result = Parallel.For(0, 10,(int i, ParallelLoopState loopstate) =>
{
    if (i == 5)
    {
        loopstate.Break();
        return;
    }
    Console.Write(string.Format("{0},", i));
});
if (result.IsCompleted)
    Console.WriteLine("Loop fully completed.");
else if (result.LowestBreakIteration.HasValue)
    Console.WriteLine("Loop not fully completed. Broken at value {0}", result.LowestBreakIteration.Value);

Output –
2,3,4,6,1,8,0,
Loop not fully completed. Broken at value 5


I hope this article helps you to know more about Parallel.For and Paralle.Foreach methods of Parallel extension of Task Parallel Library. Please leave your feedback in comments below.


Reference –

See also –