IntroductionSo what's up with these brothers in arm? The async/await keyword that is used to asynchronously wait for a task to complete. What this means in layman's term is that it (async/await) is a language implementation that is used by the currently executing thread to wait for some action or functions' execution to end without really waiting (that is waiting synchronously) for it by blocking itself from further execution . As you know, the execution of a program is synchronous in nature (I.e. : Code executes sequentially in a thread) and it starts from the main method called by the compiler on the start of the program until the termination of the program.
Occasionally, situations occur that will warrant the execution of the synchronous code in parallel by splitting it into multiple paths to be executed at the same time, either to enhance the responsiveness of the application or to improve its performance. How will the main thread be notified when the asynchronous method ends and how will it receive the result of the execution? To answer this question and see how the async/await contextual keyword enters the picture we will look at a little bit of history.
.Net 1.0In the first release of the .net framework the synchronization of parallel executed methods was implemented using Asynchronous-based parallel model (APM). In APM, an asynchronous method was implemented by two methods BeginMethodName and EndMethodName. The begin method name usually accepts the parameters required to execute the method had it been that it was implemented synchronously together with an AsyncCallback action delegate and the state object while the returning IAsyncResult while the EndMethodName accepts IAsyncResult parameter. In this model, when the work posted in the antecedent finishes its execution, it will return the IAsyncResult, call the AsyncCallback if its not null and also call its EndMethodName pair which will process the result of its antecedent method in the main thread that initiated the BeginMethodName.
public int Read(
byte  buffer, int offset, int count);
public IAsyncResult BeginRead(
byte  buffer, int offset, int count,
AsyncCallback callback, object state);
public int EndRead(IAsyncResult asyncResult);
.Net 2.0In the second release of the .net framework, the development team added the Event-based Asynchronous Pattern (EAP). This pattern was implemented using the delegates and events Api. Typically, in this pattern events are raised by the asynchronous Api executing the method (I.e: either the Thread Object or the ThreadPool Object) to notify the main thread that the asynchronous method's execution has started and to inform the main thread of its completion. Its result is returned by the AsyncCompletedEventArgs parameter of the event handler.
What then is the need for the this third option?One of the major drawback in the use of either the APM or EAP model was that its usage was so un-natural and convoluted. First of all implementing even the simplest async method will requires the developer to two two methods in both patterns. This was a hard ordeal as it moved the code away from the domain logic, focusing more on its infrastructure logic.
.Net 4.5In the latest release of the .net framework, async/await keyword was added to the base class library as a way to asynchronously wait for a void, Task or Task<Result> returning method to execute without blocking the current thread. The main advantage of this Api is in its ease of use. It enables one to write an asynchronous method the way he would normally write its synchronous counter-part without all the Mary-go round previously involved in writing such a method. Thereby allowing the code to focus on its domain logic without diversion into un-familiar territory.
public async Task DownloadAsync()
string result = await request.GetReponseAsync();
Internal ImplementationIn the previous article, we discussed the Task.ContinueWith() methods. Now the async/await keyword is implemented on top of the Task.ContinueWith() method with a twist to control further execution of the method when the awaited async method returns. Some of these twists include:
- If the calling threads' (I.e. : The thread that called the async method) SynchronizationContext.Current is not null, when the awaited method returns, the part after the await keyword will be posted to the context to be processed by the main thread. This default action can be changed by configuring the task using Task.ConfigureAwait(false) so as to prevent context switching and posting to the main thread.
- On the other hand if the SynchronizationContext.Current of the calling is null, the present TaskScheduler will then schedule the ContinueWith() either to execute on a new task or to execute on the thread that executed the antecedent task.
How the async/await deals with exceptionWhen a user mode exception occurs in the awaited method, the await keyword will propagate the exception and throw the exception at the point in which the async method is being awaited.
If multiple exceptions occurs, one of the exception (usually the last exception that occurred) will be propagated to the awaited point but the Task.Exception property will return an AggregateException object that wraps all the exceptions together in its InnerExceptions property.
NB: It is important to note that when an exception occurs in a async method, the task.IsCompleted property returns true due to the fact that the task ran to completion but in a faulted state (I.e. : The TaskStatus state will be in the faulted mode).
Finally if the task was cancelled through the use of TaskCancellationToken passed as a parameter to the async method, the task will propagate and throw OperationCancelledException at the awaited point. The task will run to completion returning true in its IsCompleted property and its TaskStatus will be in Cancelled mode.
Requirements1. It is required any task decorated with the await keyword will have an async decoration in its enclosing method.
2. Though you can decorate a method with the async keyword without implementing any awaited async method in its body, it is not advised.