C# Loops vs Parallel Foreach

Çağlar Can SARIKAYA
C# Programming
Published in
3 min readJan 5, 2022
Loop vs Parallel Loop

A loop means doing something one step at a time until the loop ends. A parallel loop, on the other hand, can do multiple steps simultaneously. Let’s explore this concept by summing integers.

Standard Loop

A basic loop sums elements of an array one by one:

var sum = 0;
for (var i = 0; i < array.Length; i++)
{
var num = array[i];
sum += num;
}
return sum;

To understand the performance, let’s benchmark this using the BenchmarkDotNet library. For demonstration purposes, we’ll sum 1000 random integers between 0 and 500.

internal class Program
{
static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<MemoryBenchmarkerDemo>();
}
}

[MemoryDiagnoser]
public class MemoryBenchmarkerDemo
{
private Random rnd = new Random();
int[] array = new int[1000];

public MemoryBenchmarkerDemo()
{
for (int i = 0; i < 1000; i++)
{
array[i] = rnd.Next(500);
}
}

[Benchmark]
public int Sum()
{
var sum = 0;
for (var i = 0; i < array.Length; i++)
{
var num = array[i];
sum += num;
}
return sum;
}
}
the result of basic for

you can review the result above.

Pseudo-Parallelism

Instead of summing one number at a time, we can sum two numbers in each loop iteration:

var counter = 0;
for (int i = 0; i < array.Length; i += 2)
{
var elementA = array[i];
var elementB = array[i+1];
counter += (elementB + elementA);
}
return counter;

Though this method processes two elements at a time, it’s not genuine parallelism but a different way of iterating.

The result of basic parallelism for loop

True Parallel Loop

For real parallelism, we can use the Parallel.ForEach method:

var options = new ParallelOptions { MaxDegreeOfParallelism = 4};
int counter = 0;
object syncLock = new object();

Parallel.ForEach(array, options, (item) =>
{
lock(syncLock)
{
counter += item;
}
});
return counter;

Here, we’re summing elements in parallel using multiple threads, and the lock ensures thread safety. However, for trivial tasks like summing numbers, the overhead of thread management may render parallel loops less efficient.

Real-World Application

To better simulate real-world scenarios, we can introduce an artificial delay, such as Thread.Sleep(10), into each loop iteration. With this delay:

  • The regular loop waits for 10 ms, 1000 times.
  • The pseudo-parallel loop waits for 10 ms, 500 times.
  • The parallel loop’s waiting time depends on the number of threads and how the workload is distributed among them.

Conclusion

Parallelism is powerful but isn’t universally beneficial. While it can speed up more complex operations, the overhead of managing multiple threads might slow down simpler tasks. Always consider the nature of the task and test the performance before opting for parallelism. Also, always ensure thread safety when accessing shared resources.

Note: Collections in C# are not inherently thread-safe. For thread-safe collections, you might want to explore BlockingCollection, ConcurrentDictionary, ConcurrentQueue, ConcurrentStack, and ConcurrentBag.

Full Compare

Resources

https://stackoverflow.com/questions/1114317/does-parallel-foreach-limit-the-number-of-active-threads

https://stackoverflow.com/a/14501752/10826057

--

--