C# Task

By FoxLearn 12/14/2024 2:11:12 PM   128
A Task in C# represents an asynchronous operation. It is part of the System.Threading.Tasks namespace and is widely used in asynchronous programming to perform tasks without blocking the main thread.

Concurrent programming is used for I/O-bound tasks (e.g., network requests, database access, or file operations) and CPU-bound tasks (e.g., heavy computations like math calculations or graphics processing). I/O-bound tasks focus on efficient waiting, while CPU-bound tasks emphasize maximizing processor usage.

Asynchronous operations are ideal for I/O-bound tasks, while parallel operations are better suited for CPU-bound tasks. In C#, the Task class supports both asynchronous and parallel operations, offering flexibility not commonly found in other languages.

Task represents a concurrent operation, while Task<TResult> represents a concurrent operation that returns a value. Task.Run executes CPU-bound code concurrently, queuing the work on the ThreadPool and returning a Task or Task<TResult> handle.

C# Task.Run

Task.Run offloads a task to a separate thread, making it suitable for CPU-bound operations.

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine($"Main thread {GetThreadId()} started");

        Task.Run(() =>
        {
            Console.WriteLine($"Worker thread {GetThreadId()} started");

            Thread.Sleep(2000); // Simulate some work

            Console.WriteLine($"Worker thread {GetThreadId()} finished");
        });

        Console.WriteLine($"Main thread {GetThreadId()} continues execution");

        Console.ReadLine();
    }

    static int GetThreadId()
    {
        return Thread.CurrentThread.ManagedThreadId;
    }
}

Output:

Main thread 1 started
Main thread 1 continues execution
Worker thread 3 started
Worker thread 3 finished

The main thread completes before the generated task. To ensure the task finishes before the program exits, Console.ReadLine is used to wait for user input.

C# Task.Delay

Task.Delay creates a task that completes after a specified time delay.

using System;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        Console.WriteLine("Task started.");

        // Task.Delay creates a delay of 3 seconds
        await Task.Delay(3000); 

        Console.WriteLine("Task completed after 3 seconds.");

        Console.ReadLine();
    }
}

Output:

Task started.
Task completed after 3 seconds.

Task.Delay creates a task that sleeps for a specified time (e.g., 3 seconds). The await operator waits for the task to complete, blocking further execution of the main program until the task finishes.

When using the await operator inside the Main method, the method must be marked with the async modifier.

C# Task.WaitAll

The Task.WaitAll method waits for all of the provided tasks to complete execution.

using System;
using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        // Creating multiple tasks
        Task task1 = Task.Run(() =>
        {
            Console.WriteLine("Task 1 started.");
            Task.Delay(2000).Wait(); // Simulate work
            Console.WriteLine("Task 1 completed.");
        });

        Task task2 = Task.Run(() =>
        {
            Console.WriteLine("Task 2 started.");
            Task.Delay(1000).Wait(); // Simulate work
            Console.WriteLine("Task 2 completed.");
        });

        // Wait for all tasks to complete
        Task.WaitAll(task1, task2);

        Console.WriteLine("All tasks have completed.");
    }
}

Output:

Task 1 started.
Task 2 started.
Task 2 completed.
Task 1 completed.
All tasks have completed.

The Task.WaitAll method ensures that the main program waits for both task1 and task2 to complete before continuing.

C# Task.ContinueWith

Task.ContinueWith creates a continuation that executes asynchronously when the target Task<TResult> completes.

using System;
using System.Threading.Tasks;

class Program
{
    static void Main(string[] args)
    {
        Task<int> task1 = Task.Run(() =>
        {
            Console.WriteLine("Task 1 started.");
            Task.Delay(2000).Wait(); // Simulate some work
            Console.WriteLine("Task 1 completed.");
            return 42; // Return a value
        });

        task1.ContinueWith((previousTask) =>
        {
            Console.WriteLine($"Task 1 result: {previousTask.Result}");
            Console.WriteLine("Task 2 started.");
            Task.Delay(1000).Wait(); // Simulate some work
            Console.WriteLine("Task 2 completed.");
        });

        Console.WriteLine("Main program continues execution.");
        Console.ReadLine();
    }
}

Output:

Main program continues execution.
Task 1 started.
Task 1 completed.
Task 1 result: 42
Task 2 started.
Task 2 completed.

C# mulitple async requests

The HttpClient class is used to send HTTP requests and receive HTTP responses from a specified resource.

using System;
using System.Net.Http;
using System.Threading.Tasks;

internal class Program
{
    static async Task Main(string[] args)
    {
        // Define the URLs to request
        string[] urls = new string[]
        {
            "https://jsonplaceholder.typicode.com/posts/1",
            "https://jsonplaceholder.typicode.com/posts/2",
            "https://jsonplaceholder.typicode.com/posts/3"
        };

        // Create an HttpClient instance
        using (HttpClient client = new HttpClient())
        {
            // Create an array of tasks for the requests
            Task<string>[] tasks = new Task<string>[urls.Length];

            // Initiate asynchronous requests
            for (int i = 0; i < urls.Length; i++)
            {
                tasks[i] = FetchDataAsync(client, urls[i]);
            }

            // Wait for all tasks to complete and get their results
            string[] results = await Task.WhenAll(tasks);

            // Output the results
            for (int i = 0; i < results.Length; i++)
            {
                Console.WriteLine($"Response from {urls[i]}: {results[i].Substring(0, 100)}..."); // Display first 100 chars
            }
        }
    }

    // Asynchronous method to fetch data from a URL
    static async Task<string> FetchDataAsync(HttpClient client, string url)
    {
        Console.WriteLine($"Requesting: {url}");
        var response = await client.GetStringAsync(url);
        return response;
    }
}

Output:

Requesting: https://jsonplaceholder.typicode.com/posts/1
Requesting: https://jsonplaceholder.typicode.com/posts/2
Requesting: https://jsonplaceholder.typicode.com/posts/3
Response from https://jsonplaceholder.typicode.com/posts/1: {
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio...
Response from https://jsonplaceholder.typicode.com/posts/2: {
  "userId": 1,
  "id": 2,
  "title": "qui est esse",
  "body": "est rerum tempore vitae\nsequi sin...
Response from https://jsonplaceholder.typicode.com/posts/3: {
  "userId": 1,
  "id": 3,
  "title": "ea molestias quasi exercitationem repellat qui ipsa sit aut"...

Multiple asynchronous HTTP requests are made by initiating them in parallel with Task[] and await Task.WhenAll(). The Task.WhenAll() method waits for all the tasks (requests) to complete and returns their results.