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
How can I limit Parallel.ForEach in C#?
The Parallel.ForEach loop in C# executes iterations across multiple threads for improved performance. However, sometimes you need to limit the degree of parallelism to control resource usage, avoid overwhelming external systems, or manage thread contention. This is accomplished using ParallelOptions.
Syntax
Following is the basic syntax for Parallel.ForEach −
Parallel.ForEach(collection, item => {
// process item
});
Following is the syntax for limiting parallelism using ParallelOptions −
Parallel.ForEach(collection,
new ParallelOptions { MaxDegreeOfParallelism = maxThreads },
item => {
// process item
});
Parameters
collection − The data source to iterate over
ParallelOptions − Configuration object for parallel execution
MaxDegreeOfParallelism − Maximum number of concurrent threads (default is processor count)
action − The delegate to execute for each item
Comparison: ForEach vs Parallel.ForEach
Example
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
class Program {
static void Main(string[] args) {
List<string> alphabets = new List<string> {
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
"U", "V", "W", "X", "Y", "Z"
};
Console.WriteLine("Sequential foreach loop:");
var stopWatch = Stopwatch.StartNew();
foreach (string alphabet in alphabets) {
Console.WriteLine("Letter: {0}, Thread Id: {1}",
alphabet, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10); // Simulate work
}
Console.WriteLine("Sequential execution time: {0} ms<br>",
stopWatch.ElapsedMilliseconds);
Console.WriteLine("Parallel.ForEach (unlimited):");
stopWatch = Stopwatch.StartNew();
Parallel.ForEach(alphabets, alphabet => {
Console.WriteLine("Letter: {0}, Thread Id: {1}",
alphabet, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10); // Simulate work
});
Console.WriteLine("Parallel execution time: {0} ms",
stopWatch.ElapsedMilliseconds);
}
}
The output of the above code is −
Sequential foreach loop: Letter: A, Thread Id: 1 Letter: B, Thread Id: 1 Letter: C, Thread Id: 1 Letter: D, Thread Id: 1 Letter: E, Thread Id: 1 Sequential execution time: 280 ms Parallel.ForEach (unlimited): Letter: A, Thread Id: 1 Letter: G, Thread Id: 4 Letter: N, Thread Id: 6 Letter: T, Thread Id: 8 Letter: B, Thread Id: 1 Letter: H, Thread Id: 4 Parallel execution time: 95 ms
Using MaxDegreeOfParallelism to Limit Threads
Example
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
class Program {
static void Main(string[] args) {
List<string> alphabets = new List<string> {
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
"K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
"U", "V", "W", "X", "Y", "Z"
};
Console.WriteLine("Limited to 2 threads:");
Parallel.ForEach(
alphabets,
new ParallelOptions { MaxDegreeOfParallelism = 2 },
alphabet => {
Console.WriteLine("Letter: {0}, Thread Id: {1}",
alphabet, Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(50); // Simulate work
}
);
}
}
The output of the above code is −
Limited to 2 threads: Letter: N, Thread Id: 4 Letter: A, Thread Id: 1 Letter: O, Thread Id: 4 Letter: B, Thread Id: 1 Letter: P, Thread Id: 4 Letter: C, Thread Id: 1 Letter: Q, Thread Id: 4 Letter: D, Thread Id: 1 Letter: R, Thread Id: 4 Letter: E, Thread Id: 1
Common Use Cases for Limiting Parallelism
| Scenario | Reason to Limit | Recommended MaxDegreeOfParallelism |
|---|---|---|
| Database operations | Avoid connection pool exhaustion | 2-4 threads |
| Web API calls | Respect rate limits | 5-10 threads |
| File I/O operations | Reduce disk thrashing | 2-3 threads |
| Memory-intensive tasks | Prevent out-of-memory errors | Environment.ProcessorCount / 2 |
Setting MaxDegreeOfParallelism Dynamically
Example
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
class Program {
static void Main(string[] args) {
List<int> numbers = new List<int>();
for (int i = 1; i <= 100; i++) {
numbers.Add(i);
}
// Limit to half the processor count
int maxThreads = Environment.ProcessorCount / 2;
if (maxThreads < 1) maxThreads = 1;
Console.WriteLine("Processor Count: {0}", Environment.ProcessorCount);
Console.WriteLine("Max Threads Used: {0}", maxThreads);
Parallel.ForEach(
numbers,
new ParallelOptions { MaxDegreeOfParallelism = maxThreads },
number => {
Console.WriteLine("Processing {0} on thread {1}",
number, System.Threading.Thread.CurrentThread.ManagedThreadId);
}
);
}
}
The output of the above code is −
Processor Count: 8 Max Threads Used: 4 Processing 1 on thread 1 Processing 26 on thread 4 Processing 51 on thread 6 Processing 76 on thread 8 Processing 2 on thread 1 Processing 27 on thread 4
Conclusion
Limiting Parallel.ForEach using MaxDegreeOfParallelism in ParallelOptions helps control resource usage and prevents system overload. This is essential when working with external resources like databases, APIs, or when memory constraints are a concern.
