What is the difference between Foreach and Parallel.Foreach in C#?

The foreach loop in C# runs on a single thread and processes items sequentially one by one. In contrast, Parallel.ForEach utilizes multiple threads to process items concurrently, potentially improving performance for CPU-intensive operations on large collections.

The key difference is that Parallel.ForEach can distribute work across multiple threads, while the standard foreach executes on a single thread. To use Parallel.ForEach, you need to import the System.Threading.Tasks namespace.

Syntax

Following is the syntax for a standard foreach loop −

foreach (var item in collection) {
   // sequential processing
}

Following is the syntax for Parallel.ForEach

Parallel.ForEach(collection, item => {
   // parallel processing
});

Using Foreach vs Parallel.ForEach

Foreach vs Parallel.ForEach Execution Standard Foreach 1 2 3 ... Single Thread - Sequential Parallel.ForEach 1 2 3 4 Multiple Threads - Concurrent Thread ID: 1 Thread IDs: 1, 3, 5, 4...

Example

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

namespace DemoApplication {
    class Demo {
        static void Main(string[] args) {
            var animals = new List<string> {
                "cat", "rat", "deer", "elephant", "lion", "tiger", "dog", "pig", 
                "buffalo", "rabbit", "horse", "cheetah", "cow", "goat", "sheep", 
                "donkey", "zebra", "wolf", "fox", "leopard", "monkey", "kangaroo", 
                "giraffe", "hippo"
            };

            var stopWatch = Stopwatch.StartNew();
            foreach (string animal in animals) {
                Console.WriteLine($"Animal Name: {animal}, Thread Id={Thread.CurrentThread.ManagedThreadId}");
            }
            stopWatch.Stop();
            Console.WriteLine($"foreach loop execution time = {stopWatch.Elapsed.TotalSeconds} seconds
"); var stopWatch2 = Stopwatch.StartNew(); Parallel.ForEach(animals, animal => { Console.WriteLine($"Animal Name: {animal}, Thread Id={Thread.CurrentThread.ManagedThreadId}"); }); stopWatch2.Stop(); Console.WriteLine($"Parallel foreach loop execution time = {stopWatch2.Elapsed.TotalSeconds} seconds"); } } }

The output of the above code is −

Animal Name: cat, Thread Id=1
Animal Name: rat, Thread Id=1
Animal Name: deer, Thread Id=1
Animal Name: elephant, Thread Id=1
Animal Name: lion, Thread Id=1
Animal Name: tiger, Thread Id=1
Animal Name: dog, Thread Id=1
Animal Name: pig, Thread Id=1
Animal Name: buffalo, Thread Id=1
Animal Name: rabbit, Thread Id=1
Animal Name: horse, Thread Id=1
Animal Name: cheetah, Thread Id=1
Animal Name: cow, Thread Id=1
Animal Name: goat, Thread Id=1
Animal Name: sheep, Thread Id=1
Animal Name: donkey, Thread Id=1
Animal Name: zebra, Thread Id=1
Animal Name: wolf, Thread Id=1
Animal Name: fox, Thread Id=1
Animal Name: leopard, Thread Id=1
Animal Name: monkey, Thread Id=1
Animal Name: kangaroo, Thread Id=1
Animal Name: giraffe, Thread Id=1
Animal Name: hippo, Thread Id=1
foreach loop execution time = 0.0129221 seconds

Animal Name: cat, Thread Id=1
Animal Name: deer, Thread Id=1
Animal Name: elephant, Thread Id=1
Animal Name: lion, Thread Id=1
Animal Name: tiger, Thread Id=1
Animal Name: dog, Thread Id=3
Animal Name: pig, Thread Id=1
Animal Name: buffalo, Thread Id=1
Animal Name: rabbit, Thread Id=1
Animal Name: sheep, Thread Id=3
Animal Name: donkey, Thread Id=3
Animal Name: goat, Thread Id=5
Animal Name: fox, Thread Id=5
Animal Name: leopard, Thread Id=5
Animal Name: cow, Thread Id=4
Animal Name: hippo, Thread Id=4
Animal Name: kangaroo, Thread Id=9
Animal Name: giraffe, Thread Id=6
Animal Name: monkey, Thread Id=5
Animal Name: horse, Thread Id=1
Animal Name: cheetah, Thread Id=1
Animal Name: zebra, Thread Id=3
Animal Name: wolf, Thread Id=3
Animal Name: rat, Thread Id=1
Parallel foreach loop execution time = 0.0092988 seconds

Performance with CPU-Intensive Operations

Example

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

class Program {
    static void Main() {
        var numbers = Enumerable.Range(1, 1000000).ToArray();
        
        Console.WriteLine("Computing squares with foreach:");
        var sw1 = Stopwatch.StartNew();
        long sum1 = 0;
        foreach (var num in numbers) {
            sum1 += num * num;
        }
        sw1.Stop();
        Console.WriteLine($"Result: {sum1}, Time: {sw1.ElapsedMilliseconds}ms");
        
        Console.WriteLine("\nComputing squares with Parallel.ForEach:");
        var sw2 = Stopwatch.StartNew();
        long sum2 = 0;
        object lockObj = new object();
        Parallel.ForEach(numbers, num => {
            long square = num * num;
            lock(lockObj) {
                sum2 += square;
            }
        });
        sw2.Stop();
        Console.WriteLine($"Result: {sum2}, Time: {sw2.ElapsedMilliseconds}ms");
    }
}

The output of the above code is −

Computing squares with foreach:
Result: 333333833333500000, Time: 15ms

Computing squares with Parallel.ForEach:
Result: 333333833333500000, Time: 8ms

Key Differences

Aspect foreach Parallel.ForEach
Thread Usage Single thread (sequential) Multiple threads (parallel)
Processing Order Guaranteed sequential order No guaranteed order
Performance Good for simple operations Better for CPU-intensive tasks
Thread Safety Not a concern Must handle shared data carefully
Overhead Minimal Thread creation and coordination

When to Use Which

Use foreach when −

  • Processing order matters

  • Operations are simple and fast

  • Working with small collections

  • Thread safety is not a concern

Use Parallel.ForEach when −

  • Processing CPU-intensive operations

  • Working with large collections

  • Order of processing doesn't matter

  • Operations are independent of each other

Conclusion

Parallel.ForEach can significantly improve performance for CPU-intensive operations on large collections by utilizing multiple threads. However, the standard foreach is simpler, maintains processing order, and has less overhead for simple operations. Choose based on your specific performance requirements and thread safety considerations.

Updated on: 2026-03-17T07:04:36+05:30

2K+ Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements