ASP.NET Core 6: Taking Advantages of Task Parallel Library
In this article, we will see the use of the Parallel class of Task Parallel Library in ASP.NET Core 6 MVC Applications. The reason for writing this article is that last week when I was discussing with the client we had a discussion regarding the use of Task Parallel Library in ASP.NET Core 6. There were a couple of scenarios we had discussed and then I thought to write my thoughts on them.
Task Parallel Library (TPL)
The TPL is introduced in .NET Framework 4.0 under the System.Threading and System.Threading.Task namespaces. The TPL has public types and APIs that simplify the process of writing parallel and concurrency code and hence improve the application's productivity. The TPL scales the degree of concurrency dynamically to most efficiently use all the processors that are available. The TPL handlers perform the following work:
- Partitioning the work
- Schedule threads on ThreadPool
- Cancellation support
- State Management
- Improvise the performance of the code and accomplish the designated work for the program
In this article, I have covered the following two scenarios
- Processing Collection Parallely
- Invoking APIs from ASP.NET Core MVC apps parallelly
public class Employee { public int EmpNo { get; set; } public string EmpName { get; set; } = String.Empty; public int Salary { get; set; } public decimal TDS { get; set; } } public static class ProcessTax { public static Employee CalculateTax(Employee emp) { System.Threading.Thread.Sleep(100); emp.TDS = emp.Salary * Convert.ToDecimal(0.1); return emp; } } public class EmployeeList : List<Employee> { public EmployeeList() { Add(new Employee() { EmpNo = 101, EmpName = "Abhay", Salary = 11000 }); Add(new Employee() { EmpNo = 102, EmpName = "Baban", Salary = 22000 }); Add(new Employee() { EmpNo = 103, EmpName = "Chaitanya", Salary = 33000 }); Add(new Employee() { EmpNo = 104, EmpName = "Deepak", Salary = 44000 }); Add(new Employee() { EmpNo = 105, EmpName = "Eshwar", Salary = 55000 }); Add(new Employee() { EmpNo = 106, EmpName = "Falgun", Salary = 66000 }); Add(new Employee() { EmpNo = 107, EmpName = "Ganpat", Salary = 77000 }); Add(new Employee() { EmpNo = 108, EmpName = "Hitesh", Salary = 88000 }); Add(new Employee() { EmpNo = 109, EmpName = "Ishan", Salary = 99000 }); Add(new Employee() { EmpNo = 110, EmpName = "Jay", Salary = 31000 }); Add(new Employee() { EmpNo = 111, EmpName = "Kaushubh", Salary = 21000 }); Add(new Employee() { EmpNo = 112, EmpName = "Lakshman", Salary = 22000 }); Add(new Employee() { EmpNo = 113, EmpName = "Mohan", Salary = 23000 }); Add(new Employee() { EmpNo = 114, EmpName = "Naveen", Salary = 24000 }); Add(new Employee() { EmpNo = 115, EmpName = "Omkar", Salary = 25000 }); Add(new Employee() { EmpNo = 116, EmpName = "Prakash", Salary = 26000 }); Add(new Employee() { EmpNo = 117, EmpName = "Qumars", Salary = 27000 }); Add(new Employee() { EmpNo = 118, EmpName = "Ramesh", Salary = 28000 }); Add(new Employee() { EmpNo = 119, EmpName = "Sachin", Salary = 29000 }); Add(new Employee() { EmpNo = 120, EmpName = "Tushar", Salary = 30000 }); Add(new Employee() { EmpNo = 121, EmpName = "Umesh", Salary = 31000 }); Add(new Employee() { EmpNo = 122, EmpName = "Vivek", Salary = 32000 }); Add(new Employee() { EmpNo = 123, EmpName = "Waman", Salary = 33000 }); Add(new Employee() { EmpNo = 124, EmpName = "Xavier", Salary = 34000 }); Add(new Employee() { EmpNo = 125, EmpName = "Yadav", Salary = 35000 }); Add(new Employee() { EmpNo = 126, EmpName = "Zishan", Salary = 36000 }); } }
public class DataViewModel { public List<Employee>? NonParallelEmployeesResult { get; set; } = new List<Employee>(); public double NonParallelTotalDuration { get; set; } public List<Employee>? ParallelEmployeesResult { get; set; } = new List<Employee>(); public double ParallelTotalDuration { get; set; } }
using System.Diagnostics; using Microsoft.AspNetCore.Mvc; namespace Core_Parallels.Controllers; public class HomeController : Controller { private readonly ILogger<HomeController> _logger; EmployeeList employees; public HomeController(ILogger<HomeController> logger) { _logger = logger; employees = new EmployeeList(); } public IActionResult Index() { DataViewModel dataView = new DataViewModel(); var timerNonParallel = Stopwatch.StartNew(); for (int i = 0; i < employees.Count; i++) { employees[i] = ProcessTax.CalculateTax(employees[i]); dataView.NonParallelEmployeesResult.Add(employees[i]); } dataView.NonParallelTotalDuration = timerNonParallel.Elapsed.TotalSeconds; var timerParallel = Stopwatch.StartNew(); Parallel.For(0, employees.Count, (int i) => { employees[i] = ProcessTax.CalculateTax(employees[i]); int j = i; i++; dataView.ParallelEmployeesResult.Add(employees[j]); }); dataView.ParallelTotalDuration = timerParallel.Elapsed.TotalSeconds; return View(dataView); } }
@model DataViewModel @{ ViewData["Title"] = "Home Page"; } <div class="text-center"> <h1 class="display-4">Taking Advantahes of Parallel.For() in ASP.NET Core </h1> <table class="table table-bordered table-striped"> <thead> <tr> <th> <h5>The Non-Parallel Execution</h5> </th> <th> <h5>The Parellel Execution</h5> </th> </tr> </thead> <tbody> <tr> <td> <table class="table table-bordered table-striped"> <thead> <tr> <th> EmpNo </th> <th> EmpName </th> <th> Salary </th> <th> TDS </th> </tr> </thead> <tbody> @foreach (var emp in Model.NonParallelEmployeesResult) { <tr> <td> @emp.EmpNo </td> <td> @emp.EmpName </td> <td> @emp.Salary </td> <td> @emp.TDS </td> </tr> } </tbody> </table> </td> <td> <table class="table table-bordered table-striped"> <thead> <tr> <th> EmpNo </th> <th> EmpName </th> <th> Salary </th> <th> TDS </th> </tr> </thead> <tbody> @foreach (var emp in Model.ParallelEmployeesResult) { <tr> <td> @emp.EmpNo </td> <td> @emp.EmpName </td> <td> @emp.Salary </td> <td> @emp.TDS </td> </tr> } </tbody> </table> </td> </tr> </tbody> <tfoot> <tr> <td> Non-Parallel Time in Seconds: @Model.NonParallelTotalDuration </td> <td> Parallel Time in Seconds: @Model.ParallelTotalDuration </td> </tr> </tfoot> </table> </div>
using System; namespace ProductCatelogService.Models { public class Product { public int ProductId { get; set; } public string ProductName { get; set; } = String.Empty; public string CategoryName { get; set; } = String.Empty; public string Manufacturer { get; set; } = String.Empty; public int Price { get; set; } } public class Products : List<Product> { public Products() { Add(new Product() {ProductId=1,ProductName="Laptop",CategoryName="Electronics IT",Manufacturer="IBM",Price=345000 }); Add(new Product() { ProductId = 2, ProductName = "Iron", CategoryName = "Electrical Home", Manufacturer = "Bajaj", Price = 5000 }); Add(new Product() { ProductId = 3, ProductName = "Mobile", CategoryName = "Electronics Communication", Manufacturer = "Samsung", Price = 34000 }); Add(new Product() { ProductId = 4, ProductName = "RAM", CategoryName = "Electronics IT", Manufacturer = "Samsung", Price = 345000 }); Add(new Product() { ProductId = 5, ProductName = "Hard Disk", CategoryName = "Electronics IT", Manufacturer = "Western Digital", Price = 345000 }); Add(new Product() { ProductId = 6, ProductName = "Power Adapter", CategoryName = "Electrical Power", Manufacturer = "HP", Price = 345000 }); Add(new Product() { ProductId = 7, ProductName = "Mixer", CategoryName = "Electrical Home", Manufacturer = "Phillipse", Price = 345000 }); Add(new Product() { ProductId = 8, ProductName = "TV", CategoryName = "Electronics Home", Manufacturer = "Samsung", Price = 345000 }); Add(new Product() { ProductId = 9, ProductName = "Sofaset", CategoryName = "Furniture", Manufacturer = "Bajaj", Price = 345000 }); Add(new Product() { ProductId = 10, ProductName = "LED Lights", CategoryName = "Electrical Home", Manufacturer = "Syska", Price = 345000 }); Add(new Product() { ProductId = 11, ProductName = "Cycle", CategoryName = "Fitness", Manufacturer = "Bajaj", Price = 345000 }); Add(new Product() { ProductId = 12, ProductName = "Keyboard", CategoryName = "Electronics IT", Manufacturer = "Microsoft", Price = 345000 }); Add(new Product() { ProductId = 13, ProductName = "Mouse", CategoryName = "Electronics IT", Manufacturer = "Microsoft", Price = 345000 }); Add(new Product() { ProductId = 14, ProductName = "Set Top Box", CategoryName = "Electrical Entertainment", Manufacturer = "D-link", Price = 345000 }); Add(new Product() { ProductId = 15, ProductName = "Water Bottel", CategoryName = "Home Appliances", Manufacturer = "TATA", Price = 345000 }); Add(new Product() { ProductId = 15, ProductName = "Monitor", CategoryName = "Electronics IT", Manufacturer = "Phillipse", Price = 345000 }); Add(new Product() { ProductId = 16, ProductName = "Extension Box", CategoryName = "Electrical Entertainment", Manufacturer = "Bajaj", Price = 345000 }); Add(new Product() { ProductId = 17, ProductName = "Headphone", CategoryName = "Electronics IT", Manufacturer = "Apple", Price = 345000 }); Add(new Product() { ProductId = 18, ProductName = "Radio", CategoryName = "Electrical Entertainment", Manufacturer = "Apple", Price = 345000 }); Add(new Product() { ProductId = 19, ProductName = "USB", CategoryName = "Electronics IT", Manufacturer = "Western Degital", Price = 345000 }); Add(new Product() { ProductId = 20, ProductName = "Memory Card", CategoryName = "Electronics IT", Manufacturer = "Western Digital", Price = 345000 }); } } }
[Route("api/[controller]")] [ApiController] public class ProductController : ControllerBase { Products Products; public ProductController() { Products = new Products(); } [HttpGet] public IActionResult Get() { return Ok(Products); } }
using System; namespace OrdersCategologService.Models { public class Order { public int OrderId { get; set; } public string CustomerName { get; set; } public string ProductName { get; set; } public int Quantity { get; set; } } public class Orders : List<Order> { public Orders() { Add(new Order() { OrderId = 20001, CustomerName = "Mahesh", ProductName = "Laptop", Quantity = 20 }); Add(new Order() { OrderId = 20002, CustomerName = "Mukesh", ProductName = "Mobile", Quantity = 10 }); Add(new Order() { OrderId = 20003, CustomerName = "Milind", ProductName = "RAM", Quantity = 8 }); Add(new Order() { OrderId = 20004, CustomerName = "Mukul", ProductName = "Hard Disk", Quantity = 40 }); Add(new Order() { OrderId = 20005, CustomerName = "Mukund", ProductName = "Mixer", Quantity = 2 }); Add(new Order() { OrderId = 20006, CustomerName = "Mohan", ProductName = "Set Top Box", Quantity = 4 }); Add(new Order() { OrderId = 20007, CustomerName = "Manohar", ProductName = "Extension Bopx", Quantity = 1 }); Add(new Order() { OrderId = 20008, CustomerName = "Madhav", ProductName = "Laptop", Quantity = 30 }); Add(new Order() { OrderId = 20009, CustomerName = "Mihir", ProductName = "Mobile", Quantity = 100 }); Add(new Order() { OrderId = 20010, CustomerName = "Madhusudhan", ProductName = "TV", Quantity = 200 }); Add(new Order() { OrderId = 20011, CustomerName = "Mrugank", ProductName = "Power Adapter", Quantity = 70 }); Add(new Order() { OrderId = 20012, CustomerName = "Mrudul", ProductName = "Sofaset", Quantity = 2 }); Add(new Order() { OrderId = 20013, CustomerName = "Manish", ProductName = "LED Lights", Quantity = 2000 }); Add(new Order() { OrderId = 20014, CustomerName = "Manav", ProductName = "Water Bottle", Quantity = 300 }); Add(new Order() { OrderId = 20015, CustomerName = "Ramesh", ProductName = "Monitor", Quantity = 10 }); Add(new Order() { OrderId = 20016, CustomerName = "Ram", ProductName = "Radio", Quantity = 8 }); Add(new Order() { OrderId = 20017, CustomerName = "Raghav", ProductName = "Monitor", Quantity = 9 }); Add(new Order() { OrderId = 20018, CustomerName = "Ramdas", ProductName = "USB", Quantity = 2000 }); Add(new Order() { OrderId = 20019, CustomerName = "Rajesh", ProductName = "Memory Catd", Quantity = 2000 }); Add(new Order() { OrderId = 20020, CustomerName = "Radhey", ProductName = "Iron", Quantity = 2000 }); } } }
[Route("api/[controller]")] [ApiController] public class OrdersController : ControllerBase { Orders Orders; public OrdersController() { Orders = new Orders(); } [HttpGet] public IActionResult Get() { return Ok(Orders); } }
public class ParallelController : Controller { public IActionResult Index() { var viewModel = new ParallelViewModel(); return View(viewModel); } [HttpPost] public IActionResult Index(ParallelViewModel data) { var viewModel = new ParallelViewModel(); Parallel.Invoke(() => { viewModel.Products = GetProducts().Result; viewModel.Orders = GetOrders().Result; }); return View("Index",viewModel); } private async Task<List<Product>> GetProducts() { List<Product> products = new List<Product>(); HttpClient http = new HttpClient(); products = await http.GetFromJsonAsync<List<Product>> ("https://localhost:7210/api/Product"); return products; } private async Task<List<Order>> GetOrders() { List<Order> orders = new List<Order>(); HttpClient http = new HttpClient(); orders = await http.GetFromJsonAsync<List<Order>> ("https://localhost:7028/api/Orders"); return orders; } }