Tasks and Parallel Programming in C#



In modern applications of C#, performance and responsiveness play an important role. Applications need to perform multiple operations simultaneously, such as downloading data, processing files, or updating the user interface.

C# provides tasks and parallel programming architecture for effectively performing such operations concurrently, taking full use of multi-core processors.

What is a Task in C#?

A Task in C# represents an operation that runs asynchronously (in the background) without blocking the main thread.

Tasks in C# are a part of the Task Parallel Library (TPL) that provide a higher-level abstraction over traditional threads.

Here are some important points on Tasks −

  • Tasks represent a unit of work that can run concurrently.
  • They can return a result using Task<TResult>.
  • They support cancellation, exception handling, and continuations.
  • Tasks can be waited for using .Wait() or awaited with async/await.

Why Use Tasks Instead of Threads?

Tasks are easier and more efficient than threads. They handle errors, cancellations, and results automatically, while threads require more manual work. Built on the Task Parallel Library (TPL), Tasks make parallel programming simpler, safer, and faster.

Creating and Running a Task in C#

In C#, there are two ways to create and start a task −

  • Using Task.Run()
  • Using Task.Factory.StartNew()

Let's understand these two methods in detail with examples.

Creating a Task Using Task.Run()

In C#, the Task.Run is used to run a piece of code asynchronously on a separate thread. It allows our program to perform work in the background without blocking the main thread. The following example demonstrates how it works −

using System;
using System.Threading.Tasks;

class Program {
   static void Main() {
      Task task = Task.Run(() => {
          Console.WriteLine("Task is running in the background.");
      });
      
      // Wait until task completes
      task.Wait();
      
      Console.WriteLine("Task Completed!");
   }
}

Following is the output

Task is running in the background.
Task Completed!

Creating a Task Using Task.Factory.StartNew()

In C#, Task.Factory.StartNew() method is used to create and start a new task immediately. It is an older way of starting tasks in C# and gives more control over task creation compared to Task.Run() The following example shows how it works −

using System;
using System.Threading.Tasks;

class Program {
   static void Main() {
     
      Task task = Task.Factory.StartNew(() => {
         Console.WriteLine("Task started using Task.Factory.StartNew()");
      });
   
      // Wait until task completes
      task.Wait();
      
      Console.WriteLine("Task Completed!");
   }
}

Following is the output

Task started using Task.Factory.StartNew()
Task Completed!

Returning a Value from a Task

In C# we use Task<TResult> when a Task returns a result. Look at the following example to learn how to use it −

using System;
using System.Threading.Tasks;

class MyProgram {
   static void Main() {
      // Task&;lt;TResult>
      Task<int> sumTask = Task.Run(() =>
      {
         int sum = 0;
         for (int i = 1; i <= 10; i++)
            sum += i;
         return sum;
      });
      Console.WriteLine("Sum: " + sumTask.Result);
   }
}

When you run this code, it will produce the following output

Sum: 55

Running Multiple Tasks in Parallel in C#

When we develop applications in C#, there are chances that sometimes we may need to execute multiple independent tasks simultaneously. In such cases, we can use the Task.Run() method to run multiple tasks in parallel or simultaneously. The following program shows how to use it −

using System;
using System.Threading.Tasks;

class Program {
   static void Main() {
      Task t1 = Task.Run(() => Console.WriteLine("Task 1 executed"));
      Task t2 = Task.Run(() => Console.WriteLine("Task 2 executed"));
      Task t3 = Task.Run(() => Console.WriteLine("Task 3 executed"));
      Task.WaitAll(t1, t2, t3);
      Console.WriteLine("All tasks completed!");
   }
}

Following is the output

Task 1 executed
Task 3 executed
Task 2 executed
All tasks completed!

Parallel Class in C#

The Parallel class in System.Threading.Tasks allows simple parallel execution using static methods like Parallel.For, Parallel.ForEach, and Parallel.Invoke.

  • Parallel.For − Executes a loop where each iteration runs in parallel on multiple threads.
  • Parallel.ForEach − Runs a foreach loop in parallel, processing multiple items from a collection at the same time.
  • Parallel.Invoke − Runs multiple independent actions or methods in parallel concurrently.

In the following examples, we show how to use these static methods for parallel execution.

Example of using Parallel.For

This program code shows the use of Parallel.For method −

using System;
using System.Threading.Tasks;

class Program {
   static void Main() {
      Parallel.For(1, 6, i => {
         Console.WriteLine($"Processing number {i}");
      });
   }
}

Following is the output

Processing number 5
Processing number 4
Processing number 3
Processing number 1
Processing number 2

Example of using Parallel.ForEach

This program code shows the use of Parallel.ForEach method −

using System;
using System.Threading.Tasks;

class Program {
   static void Main() {
      string[] names = { "John", "Jane", "Alice", "Bob" };
      Parallel.ForEach(names, name => {
         Console.WriteLine($"Hello, {name}");
      });
   }
}

Following is the output

Hello, Jane
Hello, Alice
Hello, Bob
Hello, John

Example of using Parallel.Invoke

This program code shows the use of Parallel.Invoke method −

using System;
using System.Threading.Tasks;

class Program {
  
   static void Main() {
     
      Parallel.Invoke(
         () => Console.WriteLine("Task A"),
         () => Console.WriteLine("Task B"),
         () => Console.WriteLine("Task C")
      );
   }
}

Following is the output

Task A
Task B
Task C

Conclusion

Tasks and parallel programming in C# play an important role in developing responsive and high-performance applications. By using the Task Parallel Library (TPL), developers can efficiently manage concurrent operations, easily replacing complex traditional threading.

Advertisements