Asynchronous programming in .NET 4.5

Όνομα: *
Το email μου: *
Email παραλήπτη: *
Μήνυμα: *
Τα πεδία με έντονους χαρακτήρες είναι υποχρεωτικά.
Δεν έχετε συμπληρώσει όλα τα απαιτούμενα στοιχεία Το email που δώσατε δεν είναι σωστό

Asynchronous programming has been a part of Microsoft's applications for a long time. However things tend to mature. .NET 4.5, released in August 2012, brought up C# 5 and VB 2012. And along came a new way of creating asynchronous methods. Instead of using multithreading or similar techniques, we now have access to an easier way using the key words async and await. Since a reader asked me, I am going to take a look at how these things work in today's article.

 

What is asynchronous programming?

The common way source code is handled, is synchronous (linear). That means that in order to accomplish two or more processes, that have nothing to do with each other (in other words, the sequence of these processes does not affect the result we get) we would have to wait for them all to complete one by one. Now, if the first process needed 10 seconds to complete and the second 5 seconds, the amount of time we would need to get the job done would be a total of 15 seconds. This way is no good because the second process is just sitting there waiting for the first process to complete.
 
waiting_synchronous
 
That's where the asynchronous trick comes in play. When we work asynchronously, everyone is doing their own job at the same time. When the first process begins, the second process begins as well. In the previous example, supposing that the processes do not require the same resources, that will give as a total of 10 seconds. Take a look at the next picture to get a better grip.
 
synchronous vs asynchronous
As mentioned earlier, asynchronous programming has already been developed before .NET 4.5 was released. There were some methods a developer could accomplish this, but in this article I am going to refer only to the new methods introduced in .NET 4.5 using examples from C# 5.
 

async and await

async is a keyword introduced in .NET 4.5. Accompanying a method declaration, it tells the compiler that this method is going to use asynchronous techniques. We can use it like that:
 
async void Call_Async()
{
}
 
That's all about async. There's nothing more to know in order to use it. However, if we tried to build the previous method, compiler would point a warning, stating that our async method is expected to contain the await keyword otherwards it will be considered as synchronous method. That's quite true, we have stated that our method will make use of asynchronous methods, but we are actually implementing none of them. In order for the compiler to be satisfied we should use the await keyword. For example:
 
// State the method as async, so you can use the await keyword
protected async Task Call_Async()
{
  //isOK will be set to false if GetPagesAsync fails
  bool isOK = await GetPagesAsync();
 
  //Inform the user
  if (isOK)
    AsyncLabelID.Text = "Asynchronous methods completed successfully";
  else
    AsyncLabelID.Text = "Asynchronous methods failed to complete successfully";
}
 
This is the method that will run when we press a button in the ASP.NET application we will create later on.
 
OK, what does that piece of code do? The first command calls a GetPagesAsync method like a simple program would. However, the await keyword states that you should wait for this method to complete before we go on. That's what the await keyword does. When you create and run an asynchronous operation, the basic method will still run. When it finds await, it stops till the asynchronous operation stated is complete.
 
Here's our first picture using await.
 
synchronous vs asynchronous await
 
Before we go on, you may have noticed that we changed the return type from void to Task. Using async in void methods is not a good idea since it is actually pointing to a fire and forget model. As this may lead to unexpected results, methods marked as async avoid should better be avoided.
 
 Now, you may say, "Big deal, that's what happens to synchronous programming as well, the second command waits for the first command to complete." and you may be right. However, let's take a look at the GetPagesAsync method.
 
async Task<bool> GetPagesAsync()
{
  try
  {
    HttpClient client = new HttpClient();
 
    //Create two asynchronous operations
    Task<string> getDotNetHintsStringTask = client.GetStringAsync("http://dotnethints.com");
    Task<string> getWikipediaStringTask = client.GetStringAsync("http://www.wikipedia.org");
 
    //The method will still run at the same time as the asynchronous operations do
    ComputeOtherStuff();
 
    //This is the place where the method must wait for the operations to complete
    await Task.WhenAll(getDotNetHintsStringTask, getWikipediaStringTask);
    return true;
  }
  catch
  {
    return false;
  }
}
 
 
void ComputeOtherStuff()
{
  //Just wait for two seconds
  System.Threading.Thread.Sleep(2000);
}
 
Hmmm, these methods do a lot of new stuff. If you got confused let's take a good look together, all the way from the beginning. First thing you may have noticed is that GetPagesAsync returns Task<bool>, while we might have been expecting to see a simple bool value. And what is this Task thing anyway?
 
If you haven't heard of tasks before, you may want to read this paragraph. The Task class (System.Threading.Tasks) is a part of the Task Parallel Library. Not going any further, consider a Task object as the representation of an asynchronous operation. A Task object has many methods reffering to that operation such as Start, Wait and Cancel. 
 
So, when we write 
 
Task<string> getDotNetHintsStringTask = client.GetStringAsync("http://dotnethints.com");
 
we are creating a new Task object (asynchronous operation) that is expected to carry a string value. .NET 4.5 has introduced many new asynchronous methods in order to use with its new asynchronous features like HttpClient.GetStringAsync, StreamReader.ReadAsync, BitmapEncoder.CreateAsync and many more. Asynchronous method names tend to end with the "Async" characters so they are easy to spot.
 
GetStringAsync method will return a Task containing a string value that carries the html of a web page. That happens asynchronously.
 
It may be easier now to understand why a method returning a Task<bool> value can be set to a bool value. Because it is the task's value that is set to the bool variable.
 
Great, so we have now created two asynchronous operations that download two web files. Dotnethints and Wikipedia. Being asynchronous they allow our code to go on. So we call the simple ComputeOtherStuff function that could actually do many things, but instead it will just wait for two seconds as we actually have nothing important to do in mind at the moment.
 
Then comes the await keyword, and what does it do? It says, "All right method, that's as far as you can go, now you will wait for our tasks." What tasks? The ones we tell him. Task.WhenAll(Task1, Task2, ...) will wait for all Tasks stated to complete. That would be getDotNetHintsStringTask and getWikipediaStringTask in our example. If we needed only one Task to complete, then we could simply use 
 
await getDotNetHintsStringTask;
 
This is what we did in Call_Async. Remember that?
 
bool isOK = await GetPagesAsync();
 
Now you may be wondering. Is there any point for us to create two async methods, where the first calls the second one? Why not creating only one? You may be right as, the way we mentioned earlier this command is not much different than default synchronous programming. We could instead use this method.
 
protected  void Synchronous_Call()
{
  //Get the Task instead of the value
  Task<bool> boolTask =  GetPagesAsync();
 
  bool isOK = boolTask.Result;
 
  //Inform the user
  if (isOK)
    AsyncLabelID.Text = "Asynchronous methods completed successfully";
  else
  AsyncLabelID.Text = "Asynchronous methods failed to complete successfully";
}
 
The result would be the same in that case. Remember, we are now talking ONLY about the time when you do not want to do asynchronous programming in the first method. That is when you use await in a single command.
 
bool isOK = await GetPagesAsync();
 
In that case only, we could use synchronous programming. However, most developers tend to use async and await even for that single command. That is so we can separate the asynchronous functionality from the caller method. That is the way the examples in this article will be written as well, with the exception of the last example.
 
Ok, you may still have questions but let's see what our full ASP.NET example looks like before we go on.
 
    protected void Page_Load(object sender, EventArgs e)
    {
        // RegisterAsyncTask is used instead of simply calling async void Call_Async method
        RegisterAsyncTask(new PageAsyncTask(Call_Async);
 
        //You may use ExecuteRegisteredAsyncTasks to run asynchronous tasks yourself
        //ExecuteRegisteredAsyncTasks
    }
 
    // State the method as async, so you can use the await keyword
    protected async void Call_Async()
    {
        //isOK will be set to false if GetPagesAsync fails
        bool isOK = await GetPagesAsync();
 
        //Inform the user
        if (isOK)
            AsyncLabelID.Text = "Asynchronous methods completed successfully";
        else
            AsyncLabelID.Text = "Asynchronous methods failed to complete successfully";
    }
 
    async Task<bool> GetPagesAsync()
        {
            try
            {
                HttpClient client = new HttpClient();
 
                //Create two asynchronous operations
                //These methods will asynchronously get the content of the specifies web pages
                Task<string> getDotNetHintsStringTask = client.GetStringAsync("http://dotnethints.com");
                Task<string> getWikipediaStringTask = client.GetStringAsync("http://www.wikipedia.org");
 
                //The method will still run at the same time as the asynchronous operations do
                ComputeOtherStuff();
 
                //This is the place where the method must wait for the operations to complete
                await Task.WhenAll(getDotNetHintsStringTask, getWikipediaStringTask);
                return true;
            }
            catch
            {
                return false;
            }
        }
 
 
    void ComputeOtherStuff()
        {
            //Just wait for two seconds
            System.Threading.Thread.Sleep(2000);
        }
 
 
 
Result:
Asynchronous methods completed successfully
 
When in an ASP.NET application, we can use the RegisterAsyncTask(new PageAsyncTask(method_name)) method to avoid straight calling of async void methods.
 
I think we have covered how this code works. All we need now is the AsyncLabelID Label control where we will state if the operations were successful. And one more thing. When creating ASP. NET asynchronous functionality you will need to set Async="true" in your page parameters and use asynchronous operations only within events that fire before the PreRenderComplete does.
 
Now, let's move on to a WPF application that does about the same thing as the previous example did.
 

WPF Example

 
The following example will get the same web pages as we did earlier. The story will begin when we press a button and call AsyncButton_Click.
However this time, while the pages are fetched, we will show a waiting message in the AsyncLabel Label. Since this is a WPF application we can change the label's content any time we want.
 
// State the method as async, so you can use the await keyword
private async void AsyncButton_Click(object sender, RoutedEventArgs e)
{
  //Use CallAsyncMethods to avoid use of void async in the AsyncButton_Click method
   CallAsyncMethods(); 
}
 
async Task CallAsyncMethods()
{
  //isOK will be set to false if GetPagesAsync fails
  bool isOK = await GetPagesAsync();
 
  //Inform the user
  if (isOK)
    AsyncLabel.Content = "Asynchronous methods completed successfully";
 else
   AsyncLabel.Content = "Asynchronous methods failed to complete successfully";
}
 
async Task<bool> GetPagesAsync()
{
  try
  {
    HttpClient client = new HttpClient();
 
    //Create two asynchronous operations
    //These methods will asynchronously get the content of the specifies web pages
    Task<string> getDotNetHintsStringTask = client.GetStringAsync("http://dotnethints.com");
    Task<string> getWikipediaStringTask = client.GetStringAsync("http://www.wikipedia.org");
 
   //The method will still run at the same time as the asynchronous operations do
   ComputeOtherStuff();
 
   //This is the place where the method must wait for the operations to complete
    await Task.WhenAll(getDotNetHintsStringTask, getWikipediaStringTask);
   return true;
  }
  catch
  {
  return false;
  }
}
 
 
void ComputeOtherStuff()
{
  AsyncLabel.Content = "Waiting . . . .";
}
 
 
async await wpf
 

WPF Second Example

This is our last example which will be a bit more complicated than the previous one. We will also use arguments to show that everything works just like typical methods. Take a look at the code first.
 
 protected void AsyncButton_Click(object sender, EventArgs e)
{
  CallAsyncMethod();
  //The next command will be executed even before the asynchronous method is completed 
  AsyncLabel.Content = "Waiting . . . .";
}
 
 
private async void CallAsyncMethod()
{
  string result = await GoToSlowMethod("Job Done");
  //To get past this point GoToSlowMethod should be completed
  AsyncLabel.Content = result;
}
 
private Task<string> GoToSlowMethod(string message)
{
//Create a Task that calls the SlowMethod method
return Task.Run<string>(() => SlowMethod(message));
}
 
private string SlowMethod(string message)
{
  //Wait for three seconds
  System.Threading.Thread.Sleep(3000);
  return message;
}
 
Let's go through the action sequence one by one.
  1. We press the button. AsyncButton_Click is called.
  2. CallAsyncMethod is called
  3. GoToSlowMethod is called
  4. A Task containing the SlowMethod method is run.
  5. SlowMethod is called. We are waiting for 3 seconds.
  6. In the meantime, we go back to CallAsyncMethod. We are still waiting for GoToSlowMethod.
  7. So we go back to AsyncButton_Click. AsyncLabel.Content = "Waiting . . . ."; is executed.
  8. About three seconds later SlowMethod is completed and returns "Job Done"
  9. GoToSlowMethod will return a Task containing the "Job Done" string.
  10. CallAsyncMethod sets the content of AsyncLabel to "Job Done"
  11. AsyncButton_Click completes
 
So, the result will be:
 
 
wpf async await example 2
 
 

Conclusion

.NET 4.5 presented a new technique of asynchronous programming using the async and await keywords. A method marked as async is expected to contain asyncronous operations and the await keyword. When an asyncronous operation is created the current method's code will keep executing until we reach the point where await is set for that operation. Asynchronous programming can be very helpful when dealing with time consuming independent methods.

Πίσω στο BlogΠροηγούμενοΕπόμενο

Σχόλια



    Γράψε το σχόλιό σου
    Όνομα: