C# || How To Create Multiple Tasks With Maximum Concurrency Using C#
The following is a module with functions which demonstrates how to create multiple tasks with maximum concurrency using C#.
The examples demonstrated on this page uses System.Threading.Tasks.Task to start and run tasks. They also use System.Threading.SemaphoreSlim to limit the number of tasks that can run concurrently.
The examples on this page demonstrates how to start and run multiple tasks with a maximum concurrency. It also demonstrates how to start and run multiple tasks with a return value.
1. Task – Maximum Concurrency
The example below demonstrates how to start and run multiple tasks with a maximum concurrency. For example purposes, the tasks do not return a value.
The functions shown in the example below are called asynchronously, but they can also be called synchronously.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
// Task - Maximum Concurrency var concurrentTasks = 5; var semaphore = new System.Threading.SemaphoreSlim(concurrentTasks, concurrentTasks); var tasks = new List<System.Threading.Tasks.Task>(); for (var count = 1; count <= 20; ++count) { var taskNumber = count; // Blocks execution until another task can be started. // This function also accepts a timeout in milliseconds await semaphore.WaitAsync(); // Start a task var task = System.Threading.Tasks.Task.Run(async () => { // Execute long running code try { Console.WriteLine($"Task #{taskNumber} starting..."); await System.Threading.Tasks.Task.Delay(5000); Console.WriteLine($" - Task #{taskNumber} completed!"); } catch { throw; } finally { // Signal that the task is completed // so another task can start semaphore.Release(); } }); tasks.Add(task); } Console.WriteLine($"Waiting for tasks to complete"); // Wait for all tasks to complete await System.Threading.Tasks.Task.WhenAll(tasks.ToArray()); Console.WriteLine($"All tasks completed!"); // example output: /* Task #2 starting... Task #1 starting... Task #3 starting... Task #5 starting... Task #4 starting... - Task #3 completed! - Task #1 completed! Task #6 starting... - Task #4 completed! - Task #2 completed! Task #8 starting... Task #9 starting... - Task #5 completed! Task #7 starting... Task #10 starting... - Task #6 completed! Task #11 starting... - Task #8 completed! Task #12 starting... - Task #9 completed! Task #13 starting... - Task #7 completed! - Task #10 completed! Task #14 starting... Task #15 starting... - Task #11 completed! Task #16 starting... - Task #12 completed! Task #17 starting... - Task #13 completed! Task #18 starting... - Task #14 completed! - Task #15 completed! Task #19 starting... Waiting for tasks to complete Task #20 starting... - Task #16 completed! - Task #17 completed! - Task #18 completed! - Task #20 completed! - Task #19 completed! All tasks completed! */ |
2. Task – Maximum Concurrency – Return Value
The example below demonstrates how to start and run multiple tasks with a maximum concurrency. In this example, a value is returned and retrieved from the tasks
The functions shown in the example below are called asynchronously, but they can also be called synchronously.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
// Task - Maximum Concurrency - Return Value public class Part { public string PartName { get; set; } public int PartId { get; set; } } var concurrentTasks = 5; var semaphore = new System.Threading.SemaphoreSlim(concurrentTasks, concurrentTasks); var tasks = new List<System.Threading.Tasks.Task<Part>>(); for (var count = 1; count <= 20; ++count) { var taskNumber = count; // Blocks execution until another task can be started. // This function also accepts a timeout in milliseconds await semaphore.WaitAsync(); // Start a task var task = System.Threading.Tasks.Task.Run(async () => { // Execute long running code try { Console.WriteLine($"Task #{taskNumber} starting..."); await System.Threading.Tasks.Task.Delay(5000); Console.WriteLine($" - Task #{taskNumber} completed!"); // Return result return new Part() { PartId = taskNumber, PartName = $"Part #{taskNumber}" }; } catch { throw; } finally { // Signal that the task is completed // so another task can start semaphore.Release(); } }); tasks.Add(task); } Console.WriteLine($"Waiting for tasks to complete"); // Wait for all tasks to complete await System.Threading.Tasks.Task.WhenAll(tasks.ToArray()); Console.WriteLine($"All tasks completed!"); Console.WriteLine(""); // Get the results foreach (var task in tasks) { var part = task.Result; Console.WriteLine($"Id: {part.PartId}, Name: {part.PartName}"); } // example output: /* Task #1 starting... Task #2 starting... Task #3 starting... Task #4 starting... Task #5 starting... - Task #3 completed! - Task #1 completed! Task #6 starting... - Task #5 completed! - Task #2 completed! Task #8 starting... Task #7 starting... Task #9 starting... - Task #4 completed! Task #10 starting... - Task #6 completed! Task #11 starting... - Task #8 completed! Task #12 starting... - Task #7 completed! Task #13 starting... - Task #10 completed! - Task #9 completed! Task #14 starting... Task #15 starting... - Task #11 completed! Task #16 starting... - Task #12 completed! Task #17 starting... - Task #13 completed! Task #18 starting... - Task #15 completed! - Task #14 completed! Task #19 starting... Waiting for tasks to complete Task #20 starting... - Task #17 completed! - Task #16 completed! - Task #18 completed! - Task #19 completed! - Task #20 completed! All tasks completed! Id: 1, Name: Part #1 Id: 2, Name: Part #2 Id: 3, Name: Part #3 Id: 4, Name: Part #4 Id: 5, Name: Part #5 Id: 6, Name: Part #6 Id: 7, Name: Part #7 Id: 8, Name: Part #8 Id: 9, Name: Part #9 Id: 10, Name: Part #10 Id: 11, Name: Part #11 Id: 12, Name: Part #12 Id: 13, Name: Part #13 Id: 14, Name: Part #14 Id: 15, Name: Part #15 Id: 16, Name: Part #16 Id: 17, Name: Part #17 Id: 18, Name: Part #18 Id: 19, Name: Part #19 Id: 20, Name: Part #20 */ |
3. More Examples
Below is a full example of the process demonstrated on this page!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
// ============================================================================ // Author: Kenneth Perkins // Date: May 15, 2021 // Taken From: http://programmingnotes.org/ // File: Program.cs // Description: The following demonstrates creating a task pool // ============================================================================ using System; using System.Diagnostics; using System.Linq; using System.Collections.Generic; using System.Threading.Tasks; public class Program { public class Part { public string PartName { get; set; } public int? PartId { get; set; } } static void Main(string[] args) { try { //TaskVoid().Wait(); TaskFunction().Wait(); } catch (Exception ex) { Display(ex.ToString()); } finally { Console.ReadLine(); } } public static async Task<List<Part>> TaskFunction() { var concurrentTasks = 5; var semaphore = new System.Threading.SemaphoreSlim(concurrentTasks, concurrentTasks); var tasks = new List<System.Threading.Tasks.Task<Part>>(); for (var count = 1; count <= 20; ++count) { var taskNumber = count; // Blocks execution until another task can be started. // This function also accepts a timeout in milliseconds await semaphore.WaitAsync(); // Start a task var task = System.Threading.Tasks.Task.Run(async () => { // Execute long running code try { Display($"Task #{taskNumber} starting..."); await System.Threading.Tasks.Task.Delay(5000); Display($" - Task #{taskNumber} completed!"); // Return result return new Part() { PartId = taskNumber, PartName = $"Part #{taskNumber}" }; } catch { throw; } finally { // Signal that the task is completed // so another task can start semaphore.Release(); } }); tasks.Add(task); } Display($"Waiting for tasks to complete"); // Wait for all tasks to complete await System.Threading.Tasks.Task.WhenAll(tasks.ToArray()); Display($"All tasks completed!"); Display(""); // Get the results foreach (var task in tasks) { var part = task.Result; Display($"Id: {part.PartId}, Name: {part.PartName}"); } return tasks.Select(task => task.Result).ToList(); } public static async Task TaskVoid() { var concurrentTasks = 5; var semaphore = new System.Threading.SemaphoreSlim(concurrentTasks, concurrentTasks); var tasks = new List<System.Threading.Tasks.Task>(); for (var count = 1; count <= 20; ++count) { var taskNumber = count; // Blocks execution until another task can be started. // This function also accepts a timeout in milliseconds await semaphore.WaitAsync(); // Start a task var task = System.Threading.Tasks.Task.Run(async () => { // Execute long running code try { Display($"Task #{taskNumber} starting..."); await System.Threading.Tasks.Task.Delay(5000); Display($" - Task #{taskNumber} completed!"); } catch { throw; } finally { // Signal that the task is completed // so another task can start semaphore.Release(); } }); tasks.Add(task); } Display($"Waiting for tasks to complete"); // Wait for all tasks to complete await System.Threading.Tasks.Task.WhenAll(tasks.ToArray()); Display($"All tasks completed!"); } static void Display(string message) { Console.WriteLine(message); Debug.Print(message); } }// http://programmingnotes.org/ |
QUICK NOTES:
The highlighted lines are sections of interest to look out for.
The code is heavily commented, so no further insight is necessary. If you have any questions, feel free to leave a comment below.
Leave a Reply