It has been a long time since .NET version 4.5 was released. To refresh our memory, that happened on August 15th, 2012. Yes, six years ago. Feel old yet? Well, it was not my intention to bum you out but to remind you about some of the highlights of .NET release. One of the main features that this version brought was asynchronous programming using async/await methods. Basically, the guys from Microsoft made the compiler do work that developers used to do by keeping the logical structure that resembles synchronous code.

You see, back then Windows Phone was still a thing, and making applications for these platforms had certain limitations. The main one was that Windows Phone, unlike desktop applications, introduced hard limit in which no method could block for more than 50ms. This, in turn, meant that there was no more blocking of the UI for the developers, which led to the necessity for some sort of asynchronicity in the code. .NET 4.5 represents the response to this necessity.

So, why am I writing about something that happened more than half a decade ago? Well, I noticed that even though this is an old topic, there are still a lot of engineers that struggle with the concept. To quote Mike James from iProgrammer:

Often the programmer is fully aware that what they are doing is object oriented but only vaguely aware that they are writing asynchronous code.

That is why I will try to sum up the most important parts of this style of programming in a few blogs posts. Also, we will try to identify situations in which we should use this programming style, as well as the situations when we should avoid it. So, let’s dive right into it!

Motivation and Use Cases

Essentially, this style of programming is applicable to anywhere you need the ability to do something while waiting for something else to be complete. Years of usage of this tool have actually given us the ability to realize where we should use it. It is great for user experience, and in general for event-based systems, e.g. CPU-based parallelism or working with files.

Any activity that is potentially blocking, such as access to the web, is a good candidate for this approach. If any of these blocking activities end up in a synchronous process, the entire application is blocked. On the other hand, if this activity is a part of an asynchronous process, the application can continue working with other tasks until the activity is done.

Of course, you don’t need to abuse this ability. For example, we shouldn’t asynchronously update records that are dependent. It is generally a bad idea and our data will get out of sync very quickly. Apart from that, this concept is sometimes overused. For example, if we are working on some simple actions and operations we should consider more orthodox¬†approaches. Using asynchronous concepts in these cases may, in fact, cause more overhead than benefits.

Async/Await and Return Types

The asynchronous¬†mechanism is implemented in .NET by using¬†async/await¬†keywords in our code. We use the¬†async¬†operator to mark our methods as asynchronous. Only methods with this operator methods can use¬†await¬†operator in them.¬†Await¬†operator, on the other hand, is telling to the compiler that¬†async¬†method in which it has been used can’t continue past that point until the awaited asynchronous task is complete. Basically, it suspends the execution of the method until awaited task is done. Methods that are marked with¬†async¬†operator also can be called with¬†await¬†operator from the other methods.

Another important thing to mention is that async methods must return Task class or Task class. This is because in this method await operator is applied to the Task that is returned from another async method. To sum it up, the asynchronous mechanism is in .NET implemented like this:

  • We use the async operator to mark the methods that we want to be asynchronous. These methods must return¬†Task class or Task class.
  • When we are calling methods that are marked with the async operator, we use await operator. This operator will run the task that asynchronous method returned.

How does that look into the code? Take a look at this example WebAccess.cs class:

public class WebAccess
{
public async Task<int> AccessRubiksCodeAsync()
{
HttpClient client = new HttpClient();
var getContent = client.GetStringAsync("http://rubikscode.net");
LogToConsole("Yay!");
string content = await getContent;
return content.Length;
}
private void LogToConsole(string message)
{
Console.WriteLine("At the moment I am actually listening to the new NIN song…");
Console.WriteLine("It is pretty cool…like something of David Bowie's – Blackstar.");
Console.WriteLine("message");
}
}

view raw
WebAccess.cs
hosted with ❤ by GitHub

The goal of this class is to access this website in a non-blocking manner and to get the length of the response body, for which¬†AccessRubiksCodeAsync¬†method¬†is used. We’ve put¬†Async¬†suffix at the end of the name of the function, which is the standard naming convention for asynchronous methods.¬†AccessRubiksCodeAsync¬†method is calling some operations that are synchronous, as well, like the function¬†LogToConsole.¬†It is important to realize that¬†GetStringAsync¬†method is asynchronous too and it returns¬†Task.¬†This¬†Task¬†is later run by the await operator.

Notice how we attained the structure of the synchronous code, which is awesome. Even though we are calling await operator and essentially running asynchronous task our code looks pretty neat and simple. This is one of the reasons why async/await mechanism gained a lot of popularity.

So, what happens if GetStringAsync method takes too long to answer? Here is how the workflow goes:

In the first step (marked with 1) AccessRubiksCodeAsync method creates an instance of the HttpClient and calls GetStringAsync method of this class. The goal is to download the content of the website in a form of a string. If something unexpected happens that blocks GetStringAsync method, eg. the website is taking too long to download, this method yields control to its caller. That is how it avoids blocking resources. Apart from that, this method returns Task, which AccessRubiksCodeAsync assigns to the variable getContent. Later in the code, this variable is used in combination with await operator.

Now, since we haven’t used await operator on¬†getContent¬†yet,¬†AccessRubiksCodeAsync¬†can continue with other operations that are not depending on the result of¬†getContent¬†task. So, the¬†LogToConsole¬†method can be run in a synchronous manner (step 2). This means that this method will take control, do its job and only then give control back to¬†AccessRubiksCodeAsync¬†method.

After that, this method is calling¬†getContent¬†with¬†await¬†operator (step 3). This means that at this moment this method requires the result from¬†GetStringAsync¬†method. If this¬†GetStringAsync¬†is still not ready¬†AccessRubiksCodeAsync¬†is suspending its progress and returns control to its caller. Of course, bit benefit of having this kind flow is that we “gave some time” to¬†GetStringAsync¬†method, and meanwhile, we have run synchronous parts of the code. When content is downloaded, its length is returned as a result (step 4).

Unit Testing Asynchronous Methods

Unit testing is actually one great example of how¬†async¬†methods are initiated. In this example, I’ve used xUnit, but¬†async/await¬†mechanism is supported in other unit testing frameworks like NUnit and MSTests. If you want to install xUnit to your project enter these commands in Package Manager Console:

Install-Package xunit
Install-Package xunit.runner.console
Install-Package xunit.runner.visualstudio
Update-Package

Ok, this should get you up to speed with xUnit. Now let’s take a look at our test class for¬†WebAccess¬†class¬†–¬†WebAccessTests.

public class WebAccessTests
{
[Fact]
public async Task AccessRubiksCode_NoCondition_ExpectedResult()
{
var webAccess = new WebAccess();
var result = await webAccess.AccessRubiksCodeAsync();
Assert.NotEqual(0, result);
}
}

view raw
WebAccessTests.cs
hosted with ❤ by GitHub

Now, let’s analyze important parts of this test. Firstly, notice how our test method is marked with¬†public async Task,¬†unlike¬†the standard¬†public void. This is done like this because in our test method we are actually calling¬†AccessRubiksCodeAsync¬†method of¬†WebAccess¬†class with¬†await¬†operator. We could skip this and call this method without¬†await¬†operator, and keep the¬†public void¬†notion, but this will not end up in the behavior we expected.

What will happen if we do this Рcall the async method without await operator? Well, in that case, this async method will be executed as a synchronous method, meaning it will block the thread. Again, this is bad for UI and web operations and scaling becomes impossible. This can be used as an advantage in certain situations of course, but it is important to know how this mechanism is working.

Apart from that, there are no crucial changes into test structure. We are first creating an instance of¬†WebAccess¬†class in “arrange” phase. In “act” phase we are using¬†await¬†operator to initiate¬†AccessRubiksCodeAsync¬†method and retrieve the result. Finally, in “assert” phase, we are checking the validity of the result.

Conclusion

Asynchronous programming is a somewhat standard functionality of .NET for the number of years. Still, sometimes I get the notion that less experienced programmers don’t quite get the point of it. Especially the ones that don’t have experience with some other technologies where this mechanism is directly used in the technology itself, like Node.js. Or they are familiar with it and try to use it in every situation.

In this article, I tried to explain how asynchronous programming is done in the .NET world from the high-level. In next few articles, we will go deeper into the subject and cover some other aspects of this style, as well.

Thank you for reading!


Read more posts from the author at Rubik’s Code.


Ultimate Guide to Machine Learning with Python

Everything from Python basics to the deployment of Machine Learning algorithms to production in one place.

Become a Machine Learning Superhero TODAY!