Click here to Skip to main content
15,881,204 members
Articles / General Programming / Threads
Tip/Trick

Throttling Multiple Tasks to Process Requests in C#

Rate me:
Please Sign up or sign in to vote.
4.86/5 (4 votes)
31 Oct 2018CPOL2 min read 26.1K   364   17   6
Extension method to throttle multiple Tasks in C#

Introduction

Task Parallel Library is a powerful feature introduced by Microsoft as part of the .NET Framework. This acts as a wrapper to existing ThreadPool which is now managed by CLR optimally. This saves us from the lengthy boilerplate code of maintaining and disposing the threads. There are many articles that cover the advantages of TPL and its advantages over traditional thread pool.

Here is a very good article that gives a detailed overview of TPL.

This is a short tip that will cover a common use case while using TPL: Limiting the number of tasks that execute in parallel.

Background

We use Task Parallel Library when processing multiple requests. A service or a worker process can load a set of requests and process all of them parallelly using TPL. This is a very common application of TPL, where a windows service application polls for any new requests and processes them in parallel. In some cases, we might want to control the number of concurrent processes.

About the Code

Attached is a .NET 4.5 Console application with structural methods that make use of the extension method.

He have a method fun() that takes the processId as parameter and sleeps for some random time. This will simulate over async task.

C#
public async Task fun(int processId)
       {
           await Task.Run( () =>{
               Random rand = new Random();
               Console.WriteLine("Processing " + processId);
               Thread.Sleep(rand.Next(1500));
               Console.WriteLine("Done processing - " + processId);
           });
       }

Extension Method

C#
public static async Task executeParallel<T>
      (this IEnumerable<T> items, int limit, Func<T, Task> action)
     {
         var allTasks = new List<Task>(); //Store all Tasks
         var activeTasks = new List<Task>();
         foreach (var item in items)
         {
             if (activeTasks.Count >= limit)
             {
                 var completedTask = await Task.WhenAny(activeTasks);
                 activeTasks.Remove(completedTask);
             }
             var task = action(item);
             allTasks.Add(task);
             activeTasks.Add(task);
         }
         await Task.WhenAll(allTasks); // Wait for all task to complete
     }

items denote the list of input arguments for our parallel process. In other words, we are iterating over the pending requests in the queue and throttling will be handled by the logic inside the executeParallel method.

The extension method will be called as follows:

C#
await queue.executeParallel(limit, fun); 

Main Method

The main method will take an input of number of processes. We can see the throttle in work.

C#
static void Main(string[] args)
    {
      List<int> queue = new List<int>();
      ProcessingService service = new ProcessingService();
      int n, limit = 3 ; // any arbitrary limit     
    
        Console.WriteLine("Enter number of process to Add: ");
        n = Convert.ToInt32(Console.ReadLine());
        for(int processid = 0; processid <= n; processid++)
        {         
          queue.Add(processid);
        }
      service.process(queue,limit);

      Console.Read();
    }

Throttling in Action

We can see the next process being picked up automatically and at any time, there will be at most 3 processes running.

History

  • 31st October, 2018: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
A Full-Stack Web Developer and UI/UX enthusiast.

Comments and Discussions

 
SuggestionNot a robust solution Pin
tyrotoxin4-Nov-18 19:47
tyrotoxin4-Nov-18 19:47 
QuestionInbuilt Framework options Pin
Graeme_Grant31-Oct-18 16:08
mvaGraeme_Grant31-Oct-18 16:08 
QuestionUsing the SemaphoreSlim class is a good alternative choice Pin
George Swan31-Oct-18 12:18
mveGeorge Swan31-Oct-18 12:18 
AnswerRe: Using the SemaphoreSlim class is a good alternative choice Pin
Graeme_Grant31-Oct-18 15:59
mvaGraeme_Grant31-Oct-18 15:59 
GeneralRe: Using the SemaphoreSlim class is a good alternative choice Pin
George Swan31-Oct-18 21:17
mveGeorge Swan31-Oct-18 21:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.