Microsoft has an article about creating a Task Scheduler that limits maximum concurrency:
How to: Create a Task Scheduler That Limits the Degree of Concurrency
The provided example class is clunky and kinda hard to grasp. I’ve been searching for a simple way to create a “thread pool” with limited concurrency. I previously experimented with ConcurrentBags of BackgroundWorkers – this worked, but it was also fairy complex and cumbersome.
The solution I came up with uses a Semaphore (or rather the lighter weight SemaphoreSlim type) to manage concurrency.
Simply put – you create a semaphore with a maxCount (and initialCount) equal to the max concurrency you desire. Then when you want to fire off a Task, first call semaphore.Wait(), then call semaphore.Relase() in a ContinueWith().
Contrived example:
public class LimitedAsync
{
private SemaphoreSlim _semaphore;
public LimitedAsync(int maxConcurrency)
{
// Create semaphore with maxConcurrency slots
_semaphore = new SemaphoreSlim(maxConcurrency, maxConcurrency);
}
public void DoSomethingAsync(string param)
{
//Wait for semaphore to have availablilty (blocks if semaphore is full)
_semaphore.Wait();
//Run DoSomething in a task, then release slot in semaphore
//ContinueWith is called even if DoSomething faults
Task.Factory.StartNew(() => DoSomething(param)).ContinueWith((x) => _semaphore.Release());
}
public void DoSomething(string param)
{
System.Threading.Thread.Sleep(500);
}
}