We will fix problem occurs due to incorrect use Parallelism in .NET Core
To increase application performance sometimes we use process task or work extensively in Parallel and that may lead performance issue.
When we do code, we should understand our requirement very carefully along with hardware resources those we have. We should code like that there should be less CPU usage and server should work without issues.
In .NET Core, when you’re using parallelism (like Parallel.For, Task.WhenAll, or Task.Run), you might encounter performance issues if the number of concurrent threads or tasks exceeds what your system can efficiently handle. A common issue is high CPU usage or resource contention, which can degrade overall performance, cause excessive context switching, and even lead to thread starvation or deadlocks.
Non members can access from here
Why This Problem Occurs:
- Too Many Threads: If you spawn too many threads, the overhead of context switching can overwhelm the CPU, leading to decreased performance.
- Limited Resources: A machine has a limited number of CPU cores. If you spawn more tasks than available cores, it leads to inefficient execution.
- Blocking Threads: If some tasks are blocked (e.g., due to I/O), having too many other tasks executing in parallel can worsen the problem.
- Thread Pool Saturation: The thread pool might become saturated if you don’t control the number of parallel tasks, causing tasks to be queued or delayed.
Soultion with MaxDegreeOfParallelism (Max Degree of Parallelism)
Max Degree of Parallelism (MaxDegreeOfParallelism) is a property that allows you to control the maximum number of threads that can run in parallel during operations like Parallel.For
, Task.WhenAll
, or other parallel operations.
By setting the MaxDegreeOfParallelism
, you can limit the number of concurrent threads that the system uses, ensuring that you don’t overwhelm the CPU, leading to better control over resource utilization and more predictable performance.
Match Parallelism to CPU Cores: As a rule of thumb, the number of concurrent tasks should not exceed the number of CPU cores available. For example, if your system has 4 CPU cores, setting MaxDegreeOfParallelism
to 4 or fewer will ensure that you don’t overload the CPU.
You can dynamically set this by using:
var options = new ParallelOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount // Use number of available CPU cores
};

By using MaxDegreeOfParallelism correctly we can utilize CPU core.
Implementation: Use MaxDegreeOfParallelism to Limit Parallelism
The solution to this problem is to set the MaxDegreeOfParallelism to a reasonable value that matches your hardware’s capabilities or the nature of your workload.
In .NET Core, the ParallelOptions.MaxDegreeOfParallelism
property allows you to limit the number of parallel threads in a Parallel.For
or Parallel.ForEach
loop.
using System;
using System.Threading.Tasks;
class Program
{
static void Main()
{
// Define the maximum degree of parallelism
var options = new ParallelOptions
{
MaxDegreeOfParallelism = 3 // Limit to 3 parallel threads
};
// A simple Parallel.For loop
Parallel.For(0, 100, options, i =>
{
// Simulate work
Console.WriteLine($"Task {i} is running on thread {Task.CurrentId}");
});
}
}
Output : We can see in below screen all task handled by only three threads
thread Id are 12,13,14

With MaxDegreeOfParallelism = 4
We can see in screen below 4 thread allocated for work , thread id 13,12,14,15

MaxDegreeOfParallelism in Different Contexts
- Using
Parallel.For
orParallel.ForEach
: You can limit the degree of parallelism by setting theMaxDegreeOfParallelism
in theParallelOptions
parameter.
var options = new ParallelOptions
{
MaxDegreeOfParallelism = 4 // Specify how many parallel tasks you want
};
Parallel.ForEach(myCollection, options, item =>
{
// Process each item
});
2. Using Task.WhenAll
: In scenarios like Task.WhenAll
, you don’t have direct control over the parallelism. However, you can control the concurrency by batching tasks or using a SemaphoreSlim to limit concurrent task execution.
SemaphoreSlim semaphore = new SemaphoreSlim(4); // Limit to 4 concurrent tasks
var tasks = myCollection.Select(async item =>
{
await semaphore.WaitAsync();
try
{
// Simulate async work
await ProcessItemAsync(item);
}
finally
{
semaphore.Release();
}
});
await Task.WhenAll(tasks);
Control Based on Task Type:
- I/O-bound tasks (e.g., file operations, database queries, web API calls) can often be parallelized to a higher degree because they spend a lot of time waiting.
- CPU-bound tasks (e.g., calculations, data processing) should be limited to the number of CPU cores or slightly more, as running too many threads for CPU-heavy tasks can hurt performance.
- Avoid Saturating Thread Pool: The .NET Core thread pool is shared across tasks and background operations. To avoid starving other parts of your application (like UI updates in a desktop application or background tasks in a web app), limit the number of tasks that can run in parallel.
- Monitor System Load: Be sure to monitor the system performance and adjust
MaxDegreeOfParallelism
based on real-time data. If you notice high CPU usage or task queuing, it might be necessary to lower the degree of parallelism.
Conclusion
In this post we understand how to utilize hardware properly with MaxDegreeOfParallelism
Comments
Post a Comment