Sometimes you will have code that takes a long time to execute, whether it's a web request, a complex calculation, or some other input/output operation.
If you run this code synchronously, you may find that the application will freeze whilst waiting for the code to complete.
This is where async and await come in.
Without using async/await
Let's look at a task that is guaranteed to take a long time, without using the async or await keywords:
static void Main(string[] args)
{
Console.WriteLine("Start SyncTask.");
Task.Run(SyncTask).GetAwaiter().GetResult();
}
public static Task SyncTask()
{
var result = BigSyncJob();
Console.WriteLine("This line of code does not require BigSyncJob to have finished.");
Console.WriteLine($"This line of code required BigAsyncJob to finish - {result}");
return Task.CompletedTask;
}
public static string BigSyncJob()
{
Console.WriteLine("BigSyncJob started.");
// Let's pretend this task is doing a big job, and will take 3 seconds to complete
System.Threading.Thread.Sleep(3000);
Console.WriteLine("BigSyncJob finished.");
return "Greetings from BigSyncJob!";
}
Start SyncTask.
BigSyncJob started.
BigSyncJob finished.This line of code does not require BigSyncJob to have finished.This line of code required BigAsyncJob to finish - Greetings from BigSyncJob!
Even though we did not need the result of the long running task to write one of the lines to the console, the fact that we ran it synchronously means it was forced to wait.
Ideally, we would begin executing a long running task as early as possible, and continue to execute any code that doesn't depend on it.
Then, when the long running task is complete, we can execute the remaining, dependent code.
Let's take a look at how we would do that next.
Using async/await
Here is the same example, using async and await:
static void Main(string[] args)
{
Console.WriteLine("Start AsyncTask.");
Task.Run(AsyncTask).GetAwaiter().GetResult();
}
public static async Task AsyncTask() {
Task<string> bigAsyncJob = BigAsyncJob();
Console.WriteLine("This line of code does not require BigAsyncJob to have finished.");
// Await the result of the job
var result = await bigAsyncJob; Console.WriteLine($"This line of code required BigAsyncJob to finish - {result}");
}
public static async Task<string> BigAsyncJob(){
Console.WriteLine("BigAsyncJob started.");
// Let's pretend this task is doing a big job, and will take 3 seconds to complete
await Task.Delay(3000);
Console.WriteLine("BigAsyncJob finished.");
return "Greetings from BigAsyncJob!";
}
Start AsyncTask.
BigAsyncJob started.
This line of code does not require BigAsyncJob to have finished.BigAsyncJob finished.This line of code required BigAsyncJob to finish - Greetings from BigAsyncJob!
By marking the tasks as async, we allow the task to run in parallel with any proceeding code, before the await.
This means that any code that is not dependent on the result of the long running task, can be run before the await, and therefore doesn't get halted.