C# Foreach vs Parallel Foreach
When the need is consuming list of N items. Loops are inevitable. Let’s say we have list of string contained with names. The main goal is finding the “Steve” guy.
static string[] names = new string[] { "John", ",Jakson", "Arthur", "Steve" };
static void Main(string[] args)
{
foreach (var item in names)
{
if (item == "Steve")
{
Console.WriteLine("Found the guy!");
}
}
Console.ReadKey();
}

So what we have done here is a simple loop itteration by using foreach loop. According to the goal, we have just add a condition with “Steve” string and just write a success message to the console. We need to know the completion time to compare later, so we can add a timer to find out.

What If we have much more names. Will this code run fast as above?
Not exactly. When the amount of items in array increase, elapsed of time will be increased too! Because traditional foreach runs on a single thread.
There is another thing we can try to make this itteration faster! Which is called “Parallel foreach”. Paralel foreach is basically doing same thing with traditional foreach. It is only seperates the operation between threads to complete operation faster. If we don’t give ParallelOptions, it will use all available thread as much as it needs. If we create ParallelOptions with MaxDegreeOfParallelism it will create threads the value of MaxDegreeOfParallelism.
Let’s see paralel foreach vs traditional foreach performance,
static string[] names = new string[] { "John", ",Jakson", "Arthur", "Dan","Raj",
"Carol","Steve","Mendy", "Alex","Amir", "Ali","Fatma",
"Cale","Cane", "Zayn","Faust", "Goethe", "Pep","Sydney",
"Ray" ,"Wayne","Clay", "Thomas", "Thompson","Freya", "Ragnar",
"Haaland", "Cris", "Robert", "Angela", "Micheal" ,"Pam",
"Jim", "Trent", "Max", "Lewis"};
static void Main(string[] args)
{
Console.WriteLine("Names count: "+ names.Length);
var stopWatch = Stopwatch.StartNew();
foreach (var item in names)
{
if (item == "Steve")
{
Console.WriteLine("Found the guy in ");
Console.WriteLine(stopWatch.Elapsed.TotalSeconds.ToString());
}
}
stopWatch = Stopwatch.StartNew();
Parallel.ForEach(names, name =>
{
if (name == "Steve")
{
Console.WriteLine("Found the guy in ");
Console.WriteLine(stopWatch.Elapsed.TotalSeconds.ToString());
}
});
Console.ReadKey();
}

Obviously we have a certain winner which is “Traditional Foreach”!
Itterating over simple tasks not requires any parallelism. It will make performance much worse. When tasks are not simple like this, then we can rely on Parallel Foreach! Let’s make some complex itterations.
Let’s say we have array of 10 integers and will do some long running sum operation to make execution longer. Here is the dummy operation method,
private static long GetTotalFromNumber(int number)
{
long totalCount = 0;
for (int i = number; i < 100000000; i++)
{
totalCount += i;
}
Console.WriteLine("CurrentThreadId: " + Thread.CurrentThread.ManagedThreadId);
return totalCount;
}
It basically gets number and sums until 100000000 and it writes the thread id to console.
static void Main(string[] args)
{
var limit = 10;
var numbers = Enumerable.Range(0, limit).ToList();
var stopWatch = Stopwatch.StartNew();
long totalCount = 0;
foreach (var item in numbers)
{
totalCount += GetTotalFromNumber(item);
}
Console.WriteLine("Total " + totalCount + " items");
Console.WriteLine(stopWatch.ElapsedMilliseconds);
stopWatch = Stopwatch.StartNew();
long pTotalCount = 0;
Parallel.ForEach(numbers, number =>
{
pTotalCount += GetTotalFromNumber(number);
});
Console.WriteLine("pTotal " + totalCount + " items");
Console.WriteLine(stopWatch.ElapsedMilliseconds);
Console.ReadKey();
}
As we can see above both foreach loops does the same thing. Let’s see which one is the winner!

Waow! 8 times faster then traditional foreach! But here is the thing as we mentioned before in this article. Parallel Foreach have used 10 different threads to achieve this operation. Traditional foreach used only single thread to do it.
In some reasons we don’t want our machine to consume all available threads like this. So we can limit degree of parallelism. Like,
var paralellism = new ParallelOptions {
MaxDegreeOfParallelism = 3
};
Parallel.ForEach(numbers, paralellism, number =>
{
pTotalCount += GetTotalFromNumber(number);
});

We have limited thread usage with 3. Still 2 times faster then traditional one!