Concurrency with C Sharp

Created on: 08 Jun 24 12:27 +0700 by Son Nguyen Hoang in English

Good practices to use C# with Task and more

Thumbnail 1

After a while coding in C#, I think myself need to train hard on Concurrency. After, this is such a powerful concept but I never tried to grasp the ideas properly.

I started teaching myself about Concurrency in C# using the book Concurrency in C#: Cookbook. This short article will summarize some practices and snipplets that I found useful.

Some quick notes:

  • Avoid async void (should be async Task )
  • Use Task<T> rather than ValueTask<T> (if possible)
  • Becareful with ConfigureAwait() and its implementation on UI Threads.

1. Visualize for IProgress<T> and Task

public static async Task MethodProgress(IProgress<double> progress = null){
    bool done = false;
    double percentageComplete = 0;
    while (!done){
        progress?.Report(percentageComplete);
        percentageComplete += 0.15;
        if (percentageComplete >= 1)
            break;
        await Task.Delay(TimeSpan.FromMilliseconds(40));   
    }
}

public static async Task TestProgress()
{
    var progress = new Progress<double>();

    progress.ProgressChanged += (sender, args) =>
    {
        Console.WriteLine($"Progress: {args}%");

    };
    await MethodProgress(progress);
}

2. Using Task.WhenAll()

  • The book author explicitly advice to use array (non IEnumerable instead) so he convert all to array first.
async Task<string> DownloadAllAsync(HttpClient client,
 IEnumerable<string> urls)
{
 // Define the action to do for each URL.
 var downloads = urls.Select(url => client.GetStringAsync(url));
 // Note that no tasks have actually started yet
 // because the sequence is not evaluated.
 // Start all URLs downloading simultaneously.
 Task<string>[] downloadTasks = downloads.ToArray();
 // Now the tasks have all started.
 // Asynchronously wait for all downloads to complete.
 string[] htmlPages = await Task.WhenAll(downloadTasks);
 return string.Concat(htmlPages);
}

3. Progressing tasks in order of completion

public static async Task AwaitAndProgressAysn(Task<int> task){
    int result = await task;
    Console.WriteLine(result);
}

public static async Task ProgressTasksAsyn2()
{
    Task<int> taskA = DelayAndReturnAsyn(1);
    var taskB = DelayAndReturnAsyn(2);
    var taskC = DelayAndReturnAsyn(5);
    var taskD = DelayAndReturnAsyn(3);

    var tasks = new[] { taskA, taskB, taskC, taskD };
    IEnumerable<Task> taskQuery = from t in tasks select AwaitAndProgressAysn(t);
    Task[] processingTasks = taskQuery.ToArray();
    await Task.WhenAll(processingTasks);
}

// Using Nito.AsynEx to have .OrderByCompletion()
public static async Task ProgressTasksAsyn3()
{
    Task<int> taskA = DelayAndReturnAsyn(1);
    var taskB = DelayAndReturnAsyn(2);
    var taskC = DelayAndReturnAsyn(5);
    var taskD = DelayAndReturnAsyn(3);

    var tasks = new[] { taskA, taskB, taskC, taskD };
    foreach (var task in tasks.OrderByCompletion())
    {
        var result = await task;
        Console.WriteLine(result);
    }
}
}
Back To Top