Asynchronous Programming with Async and Await in .NET

You can avoid performance bottlenecks and enhance the overall responsiveness of your application by using Asynchronous Programming.

What is Asynchronous Programming?

Asynchronous programming is writing code that allows several things to happen at the same time without “blocking”, or waiting for other things to complete. This is different from synchronous programming, in which everything happens in the order it is written.

Let’s see example. Say I have a class called ContentManagement, which has both synchronous and asynchronous methods:

public class ContentManagement  
{
    public string GetContent()
    {
        Thread.Sleep(2000);
        return "content";
    }

    public int GetCount()
    {
        Thread.Sleep(5000);
        return 4;
    }

    public string GetName()
    {
        Thread.Sleep(3000);
        return "UZVAL";
    }

    public async Task<string> GetContentAsync()
    {
        await Task.Delay(2000);
        return "content";
    }

    public async Task<int> GetCountAsync()
    {
        await Task.Delay(5000);
        return 4;
    }

    public async Task<string> GetNameAsync()
    {
        await Task.Delay(3000);
        return "UZVAL";
    }
}

Now let’s write an MVC controller, like so:

public class HomeController : Controller  
{
    [HttpGet]
    public ActionResult Index()
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        ContentManagement service = new ContentManagement();
        var content = service.GetContent();
        var count = service.GetCount();
        var name = service.GetName();

        watch.Stop();
        ViewBag.WatchMilliseconds = watch.ElapsedMilliseconds;
        return View("Index");
    }

    [HttpGet]
    public async Task<ActionResult> IndexAsync()
    {
        Stopwatch watch = new Stopwatch();
        watch.Start();
        ContentManagement service = new ContentManagement();
        var contentTask = service.GetContentAsync();
        var countTask = service.GetCountAsync();
        var nameTask = service.GetNameAsync();

        var content = await contentTask;
        var count = await countTask;
        var name = await nameTask;
        watch.Stop();
        ViewBag.WatchMilliseconds = watch.ElapsedMilliseconds;
        return View("IndexAsync");
    }
}

async : This tells the compiler that this method can run asynchronously.

await : This tells the compiler that we will ultimately need the result of the async method.

Notice what these two action methods are doing. In both cases, the action methods are calling the methods in the ContentManagement service, but in one they are doing it asynchronously.

On our Index view, we have an output : 

Time Elapsed : 10000 ms

On our IndexAsync view, we have an output : 

Time Elapsed : 5000 ms

Where did we get that number? The longest-running of the three tasks takes 5 seconds. By designing this to use async, we cut our total execution time in half! That’s a lot of speedup to be gained from writing a little extra code.

Potential Issues :

When we mark a method as async, the compiler generates a state machine in the background; this is extra code. If we write good, stable asynchronous code, the amount of time it takes to create this extra structure won’t impact us at all, since the benefits of running asynchronously outweigh the cost of building the state machine. However, if our async method doesn’t have an await, the method will run synchronously, and we will have spent extra time creating the state machine that we didn’t use.

There’s one other potential problem to be aware of. We cannot call an asynchronous method from a synchronous one. Because async and await should go together in all cases, we pretty much have to have async on all methods, all the way down. This is why we needed separate async methods in the ContentManagement class earlier.