DEV Community

Cover image for Day 14 of 30-Day .NET Challenge: Limit Concurrent Async Operations
Sukhpinder Singh
Sukhpinder Singh

Posted on

Day 14 of 30-Day .NET Challenge: Limit Concurrent Async Operations

Introduction

The article highlights the importance of limiting the concurrent asynchronous operations which in turn improves performance.

Learning Objectives

  • The common mistake all developers do

  • How to use limit concurrent async operations

  • Best Practices

Prerequisites for Developers

  • Basic understanding of C# programming language

  • Basic understanding of asynchronous programming using async await

Getting Started

The common mistake all developers do

Consider an example where the user wants to load data asynchronously within a method and it highlights the common mistake developers make

    (async item => await ProcessItem(item));
Enter fullscreen mode Exit fullscreen mode
    /// <summary>
    /// Old approach with classic async await 
    /// </summary>
    /// <returns></returns>
    public async static Task OldApproach(List<string> items)
    {
        var tasks = items.Select(async item => await ProcessItem(item));
        await Task.WhenAll(tasks);
    }
Enter fullscreen mode Exit fullscreen mode

The approach may look clean and simple but it initiates tasks for each item in the collection concurrently. This can cause system strain under heavy List items which will produce poor application performance.

Optimized approach with Concurrency Limit

Let’s transform the above method using SemaphoreSlim to limit the number of concurrent asynchronous operations. The following code snippet demonstrates the more refined approach.

    /// <summary>
    /// Optimized approach with limit concurrency
    /// </summary>
    /// <returns></returns>
    public static async Task OptimizedApproachAsync(List<string> items, int maxConcurrency = 10)
    {
        using (var semaphore = new SemaphoreSlim(maxConcurrency))
        {
            var tasks = items.Select(async item =>
            {
                await semaphore.WaitAsync(); // Limit concurrency by waiting for the semaphore.
                try
                {
                    await ProcessItem(item);
                }
                finally
                {
                    semaphore.Release(); // Release the semaphore to allow other operations.
                }
            });

            await Task.WhenAll(tasks);
        }
    }
Enter fullscreen mode Exit fullscreen mode

The aforementioned code prevents the system choked by too many concurrent tasks.

Best Practices

Please find below the best practices

Limit Concurrency

To balance system load and resources, it is recommended to use SemaphoreSlim

Avoid Blocking Calls

Avoid using .Result or .Wait() as they can lead to deadlocks and degrade performance.

Async all the way

Avoid mixing async and sync code, ensure all methods are async from top to bottom to prevent deadlock and make optimal use of resources.

Conclusion

Asynchronous programming in C# involves more than just understanding the async and await keywords; it requires more features like concurrency, resource utilization, and code structure

Complete Code on GitHub

GitHub — ssukhpinder/30DayChallenge.Net

C# Programming🚀

Thank you for being a part of the C# community! Before you leave:

If you’ve made it this far, please show your appreciation with a clap and follow the author! 👏️️

Follow us: X | LinkedIn | Dev.to | Hashnode | Newsletter | Tumblr

Visit our other platforms: GitHub | Instagram | Tiktok | Quora | Daily.dev

More content at C# Programming

Top comments (0)