Execute multiple tasks with maximum simultaneous thread
This example illustrates how to execute a task on multiple threads, but also specifying a maximum number of threads that can be running at the same time.
Main method that starts and runs the tasks
public void DoTest() { // set some constants on how we want this to run const int totalTasksToRun = 100; // total number of tasks we want to run const int maxTasksToRunSimultaneously = 50; // maximum number of tasks to be running at the same time. Console.WriteLine("Submitting Tasks"); // create a List to hold all our worker tasks List<System.Threading.Tasks.Task<MyOutput>> workerTasks = new List<System.Threading.Tasks.Task<MyOutput>>(); // create an inline function to be called after a task is complete Action<MyOutput> fnDivideByThree = (threeTask) => { Console.WriteLine(string.Format("Task {0} is divisible by 3", threeTask.TaskNum)); }; // loop a specified number of times for (int taskNum = 1; taskNum <= totalTasksToRun; taskNum++) { // need a local variable so the right number gets detected in the start of the task int localTaskNum = taskNum; // create a task and run it in a new thread System.Threading.Tasks.Task<MyOutput> returnTask = System.Threading.Tasks.Task.Run(() => this.Task1(localTaskNum)); // Make some determination on which method is to be called after the task completes. // In this example, using even/odd state. System.Threading.Tasks.Task<MyOutput> continueTask1 = null; if (taskNum % 2 == 0) { // we have an even task continueTask1 = returnTask.ContinueWith<MyOutput>(ct => this.EvenTaskCompleted(returnTask.Result), TaskContinuationOptions.AttachedToParent); } else { // we have an odd taks continueTask1 = returnTask.ContinueWith<MyOutput>(ct => this.OddTaskCompleted(returnTask.Result), TaskContinuationOptions.AttachedToParent); } // is the taskNum divisible by 3? Add another task to perform after the 1st continue task is done. if (taskNum % 3 == 0) { if (continueTask1 != null) // make sure we have a continue task defined { continueTask1.ContinueWith(ct => fnDivideByThree(returnTask.Result), TaskContinuationOptions.AttachedToParent); } } // add the returned task object to our list. workerTasks.Add(returnTask); // build a query to see how many active tasks we have var qry = from a in workerTasks where !a.IsCompleted && !a.IsFaulted && !a.IsCanceled select a; // get the count of the running tasks int runningTaskCount = qry.Count(); // do a compare against the maximum number of tasks we want to run at the same time if (runningTaskCount >= maxTasksToRunSimultaneously) { // wait until 1 of the tasks finishes System.Threading.Tasks.Task.WaitAny(qry.ToArray()); } } Console.WriteLine("All tasks submitted"); // optional- wait for all the tasks to complete. System.Threading.Tasks.Task.WaitAll(workerTasks.ToArray()); // do something with the output of all the tasks that were run Console.WriteLine("All tasks completed"); // iterate through each of the worker tasks in our List object foreach (var myTask in workerTasks) { Console.WriteLine(string.Format("Task {0} completed", myTask.Result.TaskNum)); } }
Define the task function.
private MyOutput Task1(int x) { // create the return object MyOutput myOutput = new MyOutput(); // set properties on the return object myOutput.TaskNum = x; // generate a random wait time. The _random object is initialized previously int waitTime = this._random.Next(10, 10000); // output info to console Console.WriteLine(string.Format("Starting task {0}, wait time: {1}", myOutput.TaskNum, waitTime)); // simulate some work System.Threading.Thread.Sleep(waitTime); // output info to console Console.WriteLine(string.Format("Task {0} ending", myOutput.TaskNum)); // return our output object return myOutput; }
Define some methods to be called after the tasks are completed.
private MyOutput OddTaskCompleted(MyOutput myOutput) { Console.WriteLine(string.Format("Odd task {0} ending", myOutput.TaskNum)); return myOutput; } private MyOutput EvenTaskCompleted(MyOutput myOutput) { Console.WriteLine(string.Format("Even task {0} ending", myOutput.TaskNum)); return myOutput; }
Define a class/structure to be used as the output of the tasks.
// a class/structure to use for our returned task public class MyOutput { public int TaskNum; }