Here is my explanation
class MainClass { public static async Task<String> AsyncMethod(int delay) { await Task.Delay (TimeSpan.FromSeconds(delay)); return "The method has finished it execution after waiting for " + delay + " seconds"; } public static async Task Approach1(int delay) { var response = await AsyncMethod (delay); // await just unwraps Task result Console.WriteLine (response); } public static Task Approach2(int delay) { return AsyncMethod(delay).ContinueWith(message => Console.WriteLine(message)); // you could do the same with } public static void Main (string[] args) { var operation1 = Approach1 (3); var operation2 = Approach2 (5); Task.WaitAll (operation1, operation2); Console.WriteLine("All operations are completed") } }
Ultimately, both Approach1 and Approach2 are identical pieces of code.
async/await - syntax sugar around Task API. This async method breaks it into pieces before await and after await . The "before" part is executed immediately. After the await operation is completed, the after command is executed. You can track the second part of the operation through the Task API, as you get a link to the task.
In general, async allows you to treat a method call as some long operation that you can reference through the Task API, and wait until it is finished, and continue with the other part of the code. Or through ContinueWith calling through with await is generally the same.
Before async / await / Task concepts used callbacks, but error handling was as simple as hell, Task is similar to the concept of callback , except that it makes handling exceptions easier.
In general, all this Task / async / await mantra is close to the concept of promises , if it happens when you worked with jQuery / JavaScript, there is a similar concept, there is a good question explaining how it is done there " jQuery is postponed and promises - .then () vs .done () "
Change I just found out that .NET does not have an implementation of then functionality similar to that found in jQuery / JavaScript.
The difference between ContinueWith and then is that then is able to compose the task and execute it sequentially, while ContinueWith is not, it can run the task in parallel, but this can be easily implemented through the wait construct. Here is my updated code containing the entire shebang:
static class Extensions { // Implementation to jQuery-like `then` function in .NET // According to: http://blogs.msdn.com/b/pfxteam/archive/2012/08/15/implementing-then-with-await.aspx // Further reading: http://blogs.msdn.com/b/pfxteam/archive/2010/11/21/10094564.aspx public static async Task Then(this Task task, Func<Task> continuation) { await task; await continuation(); } public static async Task<TNewResult> Then<TNewResult>( this Task task, Func<Task<TNewResult>> continuation) { await task; return await continuation(); } public static async Task Then<TResult>( this Task<TResult> task, Func<TResult,Task> continuation) { await continuation(await task); } public static async Task<TNewResult> Then<TResult, TNewResult>( this Task<TResult> task, Func<TResult, Task<TNewResult>> continuation) { return await continuation(await task); } } class MainClass { public static async Task<String> AsyncMethod1(int delay) { await Task.Delay (TimeSpan.FromSeconds(delay)); return "The method has finished it execution after waiting for " + delay + " seconds"; } public static Task<String> AsyncMethod2(int delay) { return Task.Delay (TimeSpan.FromSeconds (delay)).ContinueWith ((x) => "The method has finished it execution after waiting for " + delay + " seconds"); } public static async Task<String> Approach1(int delay) { var response = await AsyncMethod1 (delay); // await just unwraps Task result return "Here is the result of AsyncMethod1 operation: '" + response + "'"; } public static Task<String> Approach2(int delay) { return AsyncMethod2(delay).ContinueWith(message => "Here is the result of AsyncMethod2 operation: '" + message.Result + "'"); } public static void Main (string[] args) { // You have long running operations that doesn't block current thread var operation1 = Approach1 (3); // So as soon as the code hits "await" the method will exit and you will have a "operation1" assigned with a task that finishes as soon as delay is finished var operation2 = Approach2 (5); // The same way you initiate the second long-running operation. The method also returns as soon as it hits "await" // You can create chains of operations: var operation3 = operation1.ContinueWith(operation1Task=>Console.WriteLine("Operation 3 has received the following input from operation 1: '" + operation1Task.Result + "'")); var operation4 = operation2.ContinueWith(operation2Task=>Console.WriteLine("Operation 4 has received the following input from operation 2: '" + operation2Task.Result + "'")); var operation5 = Task.WhenAll (operation3, operation4) .Then(()=>Task.Delay (TimeSpan.FromSeconds (7))) .ContinueWith((task)=>Console.WriteLine("After operation3 and 4 have finished, I've waited for additional seven seconds, then retuned this message")); Task.WaitAll (operation1, operation2); // This call will block current thread; operation3.Wait (); // This call will block current thread; operation4.Wait (); // This call will block current thread; operation5.Wait (); // This call will block current thread; Console.WriteLine ("All operations are completed"); } }