Controlling the concurrency level using MaxDegreeOfParallelism in Parallel
This is another nice available in the box feature when using the Parallel class, is the ability to basically limit the concurrency for the actions that we want to execute in parallel.
Why would we ever want to do this? wouldn’t it be best if we parallel some activities as many as possible?
For certain cases, we might want to be careful for not creating too many sudden requests at the same time, a good example will be if we’re triggering a long running process in our application server, you wouldn’t want to spawn too many requests at the same time to the server, as the server may not be able to handle so many requests at the same time and not surprisingly go down due to overload. This can be categorized as DOS attack, your back end guys will hate you for this, trust me :p
To set the concurrency level of the actions that you’re going to invoke with the Parallel class is pretty simple.
Parallel.Invoke(new ParallelOptions() { MaxDegreeOfParallelism = concurrencyLevel }, actions);
Find more about the MaxDegreeOfParallelism property in msdn.
We don’t have this such of property in the TaskCreationOptions that we can simply pass for Task, but there’s a LimitedConcurrencyLevelTaskScheduler nicely available which we can achieve the same result below where i basically spawn 10 processes with 2 max concurrency level.
15-Apr-2011 21:04:33.948 - Thead#13 - Creating 10 process definitions
15-Apr-2011 21:04:33.948 - Thead#13 - Start queueing and invoking all 10 processes
15-Apr-2011 21:04:33.948 - Thead#13 - Doing something here
15-Apr-2011 21:04:33.948 - Thead#14 - Doing something here
15-Apr-2011 21:04:34.964 - Thead#13 - Doing something here
15-Apr-2011 21:04:34.964 - Thead#14 - Doing something here
15-Apr-2011 21:04:35.964 - Thead#13 - Doing something here
15-Apr-2011 21:04:35.964 - Thead#14 - Doing something here
15-Apr-2011 21:04:36.964 - Thead#13 - Doing something here
15-Apr-2011 21:04:36.964 - Thead#14 - Doing something here
15-Apr-2011 21:04:37.964 - Thead#13 - Doing something here
15-Apr-2011 21:04:37.964 - Thead#14 - Doing something here
15-Apr-2011 21:04:38.964 - Thead#13 - All processes have been completed
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ParallelTests
{
[TestClass]
public class TaskSchedulerConcurrencyTest
{
[TestMethod]
public void TestMethod1()
{
var p = new ProcessorUsingParallel();
p.DoProcess(processToCreate: 10, concurrencyLevel: 2);
}
}
public class ProcessorUsingParallel
{
public void DoProcess(int processToCreate, int concurrencyLevel)
{
SetTurboMode();
Debug("Creating {0} process definitions", processToCreate.ToString());
var actions = new Action[processToCreate];
for (int i = 0; i < processToCreate; i++)
{
actions[i] = () => DoSomething(1000);
}
Debug("Start queueing and invoking all {0} processes", processToCreate.ToString());
var options = new ParallelOptions();
options.MaxDegreeOfParallelism = concurrencyLevel;
//options.TaskScheduler = new LimitedConcurrencyLevelTaskScheduler(concurrencyLevel); -- we can achieve the same result with this
Parallel.Invoke(options, actions);
Debug("All processes have been completed");
}
private void DoSomething(int Sleep)
{
Debug("Doing something here");
Thread.Sleep(Sleep);
}
/// <summary>
/// oh i just wish the framework would have this in place like Console.WriteLine
/// </summary>
/// <param name="format"></param>
/// <param name="args"></param>
private static void Debug(string format, params object[] args)
{
System.Diagnostics.Debug.WriteLine(
string.Format("{0} - Thead#{1} - {2}",
DateTime.Now.ToString("dd-MMM-yyyy HH:mm:ss.fff"),
Thread.CurrentThread.ManagedThreadId.ToString(),
string.Format(format, args)));
}
/// <summary>
/// This is not intended for production purpose
/// </summary>
private static void SetTurboMode()
{
int t, io;
ThreadPool.GetMaxThreads(out t, out io);
Debug("Default Max {0}, I/O: {1}", t, io);
var success = ThreadPool.SetMinThreads(t, io);
Debug("Successfully set Min {0}, I/O: {1}", t, io);
}
}
}