Monday, November 26, 2012

Aync and Await in .net 4.5

Today I want to talk about a very interesting topic base on the an article from MSDN about new the syntax async and await in .net 4.5.

What is asynchronous?
I have a funny example in mind to explain this. Imagine how people communicate. When you talk to a person, you speak and then normally would wait for a response. After getting a response, you continue to speak. This is call synchronous. But for asynchronous, it is suppose to mean not synchronous. Therefore, imagine you speak to a person, you do not care for a response but instead keep talking and talking. The situation is just like your wife is nagging at you and no matter what you talk or respond, she ignore.

The asynchronous programming is a way to perform one operation to another without the need to wait for one operation to complete and respond first. While the asynchronous operation has been fired, you can either forget the respond which also known as "fire and forget", or wait for the respond later. In .net 4.5, you can easily code it with the new syntax async and await.

Async:
The async syntax is used on the method declaration only. It is used to flag that this method support asynchronous operation.
For example:
public async void Method()
{

}

When a method is declared as async, you have to use the await syntax within the method, otherwise it will become synchronous.

Another few more method declaration example:
public async Task Method() - Indicating this async method return nothing
public async Task<TMethod() - Indicating this async method return the specified type

Note:
public async void Method() VS public async Task Method()
Both method declaration above are not the same. Void return method is normally used in event handler. You use it only when you want to create a "fire and forget" method. Void return method is not awaitable.
Task return method is an async method that return nothing. You should use it to create awaitable void method.


Await:
The await syntax is used on the method which has the return type is Task<T> or awaitable.
For example:
int value = await Increment(random.Next(100));

Here is how my awaitable method declaration:
private async Task<int> Increment(int value)
{

}

You should expect to see the (awaitable) word in the tooltip after mouse over to your method.



Every async method must use await syntax at least once within it. Otherwise, you will get the following warning:

"This async method lacks 'await' operators and will run synchronously."

A usual async method with Task return type implementation should look like this:

public async Task Method()
{
    await Task.Run(() =>
    {
        Thread.Sleep(10000);
        Debug.WriteLine("This is an async method with Task return type.");
    });

}

A normal async method with Task specified type return should look like this:

public async Task<string> Method()
{
    string value = "This is an async method with Task<string> return type.";

    return await Task.FromResult<string>(value);

}

I have created a sample WPF window application to test with the new syntaxes.
The sample idea is to perform 4 value increment tasks with random value first before proceed to wait for result and display to the UI.

I have put comments into my code below to show how asynchronous work.

Random random = new Random();
for (int i = 0; i < 1000; i++)
{
    //Task 1 has begin
    Task<int> getIncrementTask1 = Increment(random.Next(100));

    //Task 2 has begin while Task 1 is still working
    Task<int> getIncrementTask2 = Increment(random.Next(100));

    //Task 3 has begin while Task 2 is still working but Task 1 is completed
    Task<int> getIncrementTask3 = Increment(random.Next(100));

    //Task 4 has begin while Task 3 is still working but Task 1 and Task 2 are completed
    Task<int> getIncrementTask4 = Increment(random.Next(100));

    //Await for Task to complete, then get its value
    int incrementValue1 = await getIncrementTask1;
    int incrementValue2 = await getIncrementTask2;
    int incrementValue3 = await getIncrementTask3;
    int incrementValue4 = await getIncrementTask4;

    //Use dispatcher to update the UI to make it responsive
    Dispatcher.Invoke(() =>
    {
        MessageText.Text += "\n Increment value: " + incrementValue1.ToString();
        MessageText.Text += "\n Increment value: " + incrementValue2.ToString();
        MessageText.Text += "\n Increment value: " + incrementValue3.ToString();
        MessageText.Text += "\n Increment value: " + incrementValue4.ToString();
    });

    Task<long> getExponentialTask1 = Exponential(incrementValue1);
    Task<long> getExponentialTask2 = Exponential(incrementValue2);
    Task<long> getExponentialTask3 = Exponential(incrementValue3);
    Task<long> getExponentialTask4 = Exponential(incrementValue4);

    //Dispatcher invoke the UI update asynchrounously
    //Update the UI first if get exponential task 1 is completed first
    DispatcherOperation op1 = Dispatcher.InvokeAsync(async () =>
    {
        MessageText.Text += "\n Exponential value: " + (await getExponentialTask1).ToString);
    });

    DispatcherOperation op2 = Dispatcher.InvokeAsync(async () =>
    {
        MessageText.Text += "\n Exponential value: " + (await getExponentialTask2).ToString);
    });

    DispatcherOperation op3 = Dispatcher.InvokeAsync(async () =>
    {
        MessageText.Text += "\n Exponential value: " + (await getExponentialTask3).ToString);
   });

    DispatcherOperation op4 = Dispatcher.InvokeAsync(async () =>
    {
        MessageText.Text += "\n Exponential value: " + (await getExponentialTask4).ToString);
    });

    await op1;
    await op2;
    await op3;
    await op4;

    //Scroll the text box to the end after all operations are completed
    Dispatcher.Invoke(() =>
    {
        MessageText.ScrollToEnd();
    });
}

Here are my awaitable methods:

private async Task<int> Increment(int value)
{
    //Slow the time down to see the async work
    //Thread.Sleep(1000);
    return await Task.FromResult<int>(value + 1);
}

private async Task<long> Exponential(int value)
{
    //Slow the time down to see the async work
    //Thread.Sleep(1000);
    return await Task.FromResult<long>(value * value);
}


Error handling:
What if there is an error occurred during the async call?
No worry, the Task<T> object has IsFaulted property and Exception property. If there is any unhandled exception was thrown, the IsFaulted property value will be flagged as true, and the exception detail will be available in the Exception property.

Here are the sample code to check if a Task is faulted or not.
When a Task is in faulted state, you cannot await it to get its result. It will throw you an exception.

if (getIncrementTask1.IsFaulted || getIncrementTask2.IsFaulted || getIncrementTask3.IsFaulted || getIncrementTask4.IsFaulted)
{
    Dispatcher.Invoke(() =>
    {
        MessageText.Text += "\n Error has occurred!";
    });
}
else
{
    //Await for Task 1 to complete if it not, then get its value
    incrementValue1 = await getIncrementTask1;
    incrementValue2 = await getIncrementTask2;
    incrementValue3 = await getIncrementTask3;
    incrementValue4 = await getIncrementTask4;
}


There are many APIs support async methods in .net 4.5. Below are the API list referred from MSDN.
As long as you see any API return type is Task<T>, they are awaitable and support async call.

Web accessHttpClient , SyndicationClient
Working with filesStorageFile, StreamWriter, StreamReader, XmlReader
Working with imagesMediaCapture, BitmapEncoder, BitmapDecoder
WCF programmingSynchronous and Asynchronous Operations
Working with socketsSocket


I commonly work on WCF, and I notice I can now generate task-based WCF operation with .net 4.5 and use it with the new await syntax.



Feel free to download my sample project if you like. DOWNLOAD




1 comment:

Send Transactional SMS with API

This post cover how to send transactional SMS using the Alibaba Cloud Short Message Service API. Transactional SMS usually come with One Tim...