Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
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
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.
