Async and await keywords are introduced in .Net 4.5 are the heart of Asynchronous programming and does all the magic.
Let’s discuss with a simple example.
Consider we are going to perform a very complex I/O operation which reads an external file over network and renames the file and copies the renamed file in another folder of a different machine in network. Waiting for this operation to complete for just 1 file itself will take a long time (Depending upon network traffic, I/O speed and latency) and consider the same for thousands of file. While performing this resource intensive operation your UI will hang and your application will stop responding, since all UI related activity will always have Thread affinity (means they all run in same thread). To cope this problem we can use async and await keywords in combination.
Well, I am not going to discuss more about async and await in details, since the post is intended to demonstrate how to establish asynchronous execution using them.
In short, async will perform make a method to execute asynchronously, meaning it return to the caller immediately and await within async method will ensure the called async method is done with what it’s doing. I know it sounds very simple than what it is, you can read more about it from MSDN
Let’s start writing the same code which we discussed in my previous post
Operation
I am trying to execute an SQL query (Insert query) 20 times and all I am planning to do is to test if the SQL server is fast enough to respond and inserts the record. All I am trying to achieve is maximum parallelism of operation (Inserting of record at same time). Here is the code which we discussed in our last post, which does parallel execution using Parallel.ForCode using Parallel.For
public static void WithTPL(int ThreadCount) { //Create Parallel.For to execute the task Parallel.For(0, ThreadCount, i => { ConnectDBAndExecuteQuery(i); }); }Code for ConnectDBAndExecuteQuery()
public static void ConnectDBAndExecuteQuery(int ThreadNumber) { try { string sqlQuery = "insert into tblMasterLookup Values (" + ThreadNumber + ",'Test','2.0','Myapplication',GetDate()) waitfor delay '00:00:30'"; string connectionString = @"Server=.\SQLEXPRESS;Database=AUTODATA;Password=abc123;User ID=sa"; using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); using (SqlCommand command = new SqlCommand(sqlQuery, connection)) { command.CommandTimeout = 80; command.ExecuteNonQuery(); Console.WriteLine("Executed Thread.. " + Thread.CurrentThread.ManagedThreadId); } } } catch (Exception e) { Console.WriteLine(e.Message); } }
Code using Async and Await
This time we are going to leverage the power of Async and Await, but here I am also going to use asynchronous ExecuteNonQuery method named ExecuteNonQueryAsync() Well this method is something shipped by Microsoft .Net and not by me JShort history
Currently in Windows 8, all the resource intensive operations which ever takes more than 50 seconds are converted as asynchronous methods. You can see a list of asynchronous supported members from here Back to code using async and await coding, as mentioned, I am going to use ExecuteNonQueryAsync, which means I need to make my method as Async and have to wait for ExecuteNonQueryAsync to complete its operation using await. Here is the modified code of ConnectDBAndExecuteQuery Code for ConnectDBAndExecuteQueryAsyncpublic static async Task ConnectDBAndExecuteQueryAsync(int ThreadNumber) { try { string sqlQuery = "insert into tblMasterLookup Values (" + ThreadNumber + ",'Test','2.0','Myapplication',GetDate()) waitfor delay '00:00:30'"; string connectionString = @"Server=.\SQLEXPRESS;Database=AUTODATA;Password=abc123;User ID=sa"; using (SqlConnection connection = new SqlConnection(connectionString)) { connection.Open(); using (SqlCommand command = new SqlCommand(sqlQuery, connection)) { Console.WriteLine("Executed Thread.. " + Thread.CurrentThread.ManagedThreadId); command.CommandTimeout = 80; await command.ExecuteNonQueryAsync(); } } } catch (Exception e) { Console.WriteLine(e.Message); } }As you can see now, I have given my method name as ConnectDBAndExecuteQueryAsync which is recommended by Microsoft coding convention. And here is the code to call the asynchronous method
public static void UsingAsyncAwait(int ThreadCount) { for (int i = 0; i < ThreadCount; i++) { Task task = ConnectDBAndExecuteQueryAsync(i); } }
Performance Improvement with async and await
The whole reason for going async and await is for performance improvement by running resource intensive operations in parallel, well here is the improved performance and parallelism we achieved using async and await. With Parallel.For and Async/await, we could see lots and lots of improvement. It took just 140 milliseconds to perform same insert operation for async/await which took 18 seconds in Parallel.For.Multithreading Async and Await
By default async and await are single threaded, which means while you execute the above code you can see the result clearly as shown below All the execution is happening with single thread. In order to make the async/await to run in multithread, we need to make use of Task.Run or Task.Factory.StartNew Here is the codepublic static void UsingAsyncAwaitWithTask(int ThreadCount) { Parallel.For(0, ThreadCount, i => { Task.Factory.StartNew(() => { return ConnectDBAndExecuteQueryAsync(i); }); }); }While executing the above code, the output looks something like this The thread number will change for each and every run and also for you and me.
I’m trying like below but I’m getting connection closed error.
using (SqlConnection connection = (SqlConnection)SqlHelper.OpenConnection())
{
Parallel.For(0, arr.Count(), i =>
{
Task.Factory.StartNew(() =>
{
return AzureToSqlAsync(arr[i], connection);
});
});
}
And :
private async Task AzureToSqlAsync(string query, SqlConnection connection)
{
try
{
using (SqlCommand command = new SqlCommand(query, connection))
{
command.CommandTimeout = 80;
await command.ExecuteNonQueryAsync();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}