0
0
CsharpHow-ToBeginner · 3 min read

How to Use Parallel.ForEach in C# for Concurrent Loops

Use Parallel.ForEach in C# to run a loop where each iteration can execute in parallel on multiple threads. It takes a collection and an action delegate to perform work concurrently, speeding up processing for independent tasks.
📐

Syntax

The Parallel.ForEach method runs a loop over a collection in parallel. It requires two main parts:

  • Collection: The list or array to loop over.
  • Action: A delegate (usually a lambda) that defines what to do with each item.

Optionally, you can provide ParallelOptions to control parallelism.

csharp
Parallel.ForEach(collection, item => {
    // work to do with each item
});
💻

Example

This example shows how to use Parallel.ForEach to print numbers from 1 to 5 concurrently. Each number is processed in parallel, which can speed up work if the action is time-consuming.

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

class Program
{
    static void Main()
    {
        var numbers = new List<int> {1, 2, 3, 4, 5};

        Parallel.ForEach(numbers, number =>
        {
            Console.WriteLine($"Processing number {number} on thread {System.Threading.Thread.CurrentThread.ManagedThreadId}");
        });
    }
}
Output
Processing number 1 on thread 10 Processing number 2 on thread 11 Processing number 3 on thread 12 Processing number 4 on thread 13 Processing number 5 on thread 14
⚠️

Common Pitfalls

Common mistakes when using Parallel.ForEach include:

  • Modifying shared data without synchronization: This can cause race conditions and incorrect results.
  • Using Parallel.ForEach for very fast or simple tasks: Overhead of parallelism may slow down the program.
  • Assuming order: The order of processing is not guaranteed in parallel loops.

Always ensure thread safety and use parallelism only when it benefits performance.

csharp
/* Wrong: Modifying shared list without lock */
var results = new List<int>();
Parallel.ForEach(numbers, number =>
{
    results.Add(number * 2); // Not thread-safe
});

/* Right: Use thread-safe collection or locking */
var resultsSafe = new System.Collections.Concurrent.ConcurrentBag<int>();
Parallel.ForEach(numbers, number =>
{
    resultsSafe.Add(number * 2); // Thread-safe
});
📊

Quick Reference

  • Parallel.ForEach(collection, action): Runs action on each item in collection in parallel.
  • ParallelOptions: Control max threads and cancellation.
  • Thread safety: Use thread-safe collections or locks when sharing data.
  • Order: No guaranteed order of execution.

Key Takeaways

Use Parallel.ForEach to run loop iterations concurrently for better performance on independent tasks.
Always ensure thread safety when accessing shared data inside Parallel.ForEach.
Parallel.ForEach does not guarantee the order of execution.
Avoid parallelism for very quick or simple operations to prevent overhead.
Use ParallelOptions to control parallelism behavior like max threads or cancellation.