Asynchronous programming in .net 4.5 with c#


Published on

Published in: Technology, Design
  • Be the first to comment

No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Asynchronous programming in .net 4.5 with c#

  1. 1. Binu Bhasuran Microsoft MVP Visual C# Facebook Blog
  2. 2. Threading model was introduced in which release of .NET framework? 1.0 1.1 2.0 3.5 3.5 SP1 2) Interlocked class introduced in which release of .NET framework? 2.0 4.0 3.5 SP1 4.5 1.1 3) Can you stop an Asynchronous delegate? Yes No It depends on implementation. It depends on .NET framework version. 4) By Default .NET application starts how many threads? 1 2 3 Depends on processor architecture.
  3. 3. Asynchronous operations are operations which are initiated and then continue concurrently with the invoking code. When conforming to the .NET Task-Based Asynchronous Pattern (TAP), asynchronous methods return a task that represents the ongoing operation and allows waiting for its eventual outcome. Invoking and then asynchronously waiting for a task- returning method to complete is as simple as “await myAsyncMethod();”. The control flow is completely unaltered, and there are no callbacks in sight because the compiler takes care of creating and signing them up.
  4. 4. Convert synchronous code into asynchronous code Perform tasks without blocking the UI Run concurrent tasks Implement cancellation and polling features Generate a DLL library that exposes asynchronous methods
  5. 5. Initiation and completion of an asynchronous operation in the TAP are represented by a single method, and thus there is only one method to name. This is in contrast to the IAsyncResult pattern, or APM pattern, where BeginMethodName and EndMethodName methods are required, and in contrast to the event-based asynchronous pattern, or EAP, where a MethodNameAsync is required in addition to one or more events, event handler delegate types, and EventArg-derived types. Asynchronous methods in the TAP are named with an “Async” suffix that follows the operation’s name, e.g. MethodNameAsync.
  6. 6. The singular TAP method returns either a Task or a Task<TResult>, based on whether the corresponding synchronous method would return void or a type TResult, respectively. (If adding a TAP method to a class that already contains a method MethodNameAsync, the suffix “TaskAsync” may be used instead, resulting in “MethodNameTaskAsync”.)
  7. 7. public class MyClass { public IAsyncResult BeginRead( byte [] buffer, int offset, int count, AsyncCallback callback, object state); public int EndRead(IAsyncResult asyncResult); }
  8. 8. public class MyClass { public void ReadAsync(byte [] buffer, int offset, int count); public event ReadCompletedEventHandler ReadCompleted; } public delegate void ReadCompletedEventHandler( object sender, ReadCompletedEventArgs eventArgs); public class ReadCompletedEventArgs : AsyncCompletedEventArgs { public int Result { get; } }
  9. 9. TAP counterpart would expose the following single method: public class MyClass { public Task<int> ReadAsync(byte [] buffer, int offset, int count); }
  10. 10. The parameters to a basic TAP method should be the same parameters provided to the synchronous counterpart, in the same order. However, “out” and “ref” parameters are exempted from this rule and should be avoided entirely. Any data that would have been returned through an out or ref parameter should instead be returned as part of the returned Task<TResult>’s Result, utilizing a tuple or a custom data structure in order to accommodate multiple values.
  11. 11. To expose a cancelable asynchronous operation, a TAP implementation provides an overload that accepts a CancellationToken after the synchronous counterpart method’s parameters. By convention, the parameter should be named “cancellationToken”.
  12. 12. public Task<int> ReadAsync( byte [] buffer, int offset, int count, CancellationToken cancellationToken); If the token has cancellation requested and the asynchronous operation is able to respect that request, the returned task will end in the TaskStatus.Canceled state; there will be no available Result and no Exception
  13. 13. In the TAP, progress is handled through an IProgress<T> interface passed into the asynchronous method as a parameter named “progress”. Providing the progress interface at the time of the asynchronous method’s invocation helps to eliminate race conditions that result from incorrect usage where event handlers incorrectly registered after the invocation of the operation may miss updates. More importantly, it enables varying implementations of progress to be utilized, as determined by the consumer
  14. 14. public Task<int> ReadAsync( byte [] buffer, int offset, int count, IProgress<int> progress);
  15. 15. A single IProgress<T> implementation, Progress<T>, is provided built-in (more implementations may be provided in the future). The Progress<T> class is declared as follows: public class Progress<T> : IProgress<in T> { public Progress(); public Progress(Action<T> handler); protected OnReport(T value); public event ProgressEventHandler<T> ProgressChanged; }
  16. 16. public Task MethodNameAsync(…); public Task MethodNameAsync(…, CancellationToken cancellationToken); public Task MethodNameAsync(…, IProgress<T> progress); public Task MethodNameAsync(…, CancellationToken cancellationToken, IProgress<T> progress);
  17. 17. PatternsandTypes From APM to Tasks From Tasks to APM Tasks and the Event-based Asynchronous Pattern (EAP) Tasks and WaitHandles From Tasks to WaitHandles
  18. 18. The .NET Framework 1.0 saw the introduction of the IAsyncResult pattern, otherwise known as the Asynchronous Programming Model (APM) pattern, or the Begin/End pattern. The .NET Framework 2.0 then brought with it the event-based asynchronous pattern (EAP). The new TAP deprecates both of its predecessors, while at the same time providing the ability to easily build migration routines from the APM and EAP to TAP.
  19. 19. The APM pattern relies on two corresponding methods to represent an asynchronous operation: BeginMethodName and EndMethodName. At a high- level, the begin method accepts as parameters to the method the same parameters that would be supplied to the MethodName synchronous method counterpart, as well as also accepting an AsyncCallback delegate and an object state
  20. 20. The begin method then returns an IAsyncResult, which returns from its AsyncState property the object state passed to the begin method. When the asynchronous operation completes, the IAsyncResult’s IsCompleted will start returning true, and its AsyncWaitHandle will be set.
  21. 21. Additionally, if the AsyncCallback parameter to the begin method was non-null, the callback will be invoked and passed the same IAsyncResult that was returned from the begin method. When the asynchronous operation does complete, the EndMethodName method is used to join with the operation, retrieving any results or forcing any exceptions that occurred to then propagate. There are further details around the IAsyncResult’s CompletedSynchronously property that are beyond the scope of this document; for more information, see MSDN
  22. 22. Given the very structured nature of the APM pattern, it is quite easy to build a wrapper for an APM implementation to expose it as a TAP implementation. In fact, the .NET Framework 4 includes helper routines in the form of TaskFactory.FromAsync to provide this translation.
  23. 23. Consider the .NET Stream class and its BeginRead/EndRead methods, which represent the APM counterpart to the synchronous Read method: 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);
  24. 24. Utilizing FromAsync, we can implement a TAP wrapper for this method as follows: public static Task<int> ReadAsync( this Stream stream, byte [] buffer, int offset, int count) { if (stream == null) throw new ArgumentNullException(“stream”); return Task<int>.Factory.FromAsync(stream.BeginRead, stream.EndRead, buffer, offset, count, null); }
  25. 25. This implementation that utilizes FromAsync is effectively equivalent to the following: public static Task<int> ReadAsync( this Stream stream, byte [] buffer, int offset, int count) { if (stream == null) throw new ArgumentNullException(“stream”); var tcs = new TaskCompletionSource<int>(); stream.BeginRead(buffer, offset, count, iar => { try { tcs.TrySetResult(stream.EndRead(iar)); } catch(OperationCanceledException) { tcs.TrySetCanceled(); } catch(Exception exc) { tcs.TrySetException(exc); } }, null); return tcs.Task; }
  26. 26. For cases where existing infrastructure expects code to implement the APM pattern, it is also important to be able to be able to take a TAP implementation and use it where an APM implementation is expected.
  27. 27. public static IAsyncResult AsApm<T>( this Task<T> task, AsyncCallback callback, object state) { if (task == null) throw new ArgumentNullException(“task”); var tcs = new TaskCompletionSource<T>(state); task.ContinueWith(t => { if (t.IsFaulted) tcs.TrySetException(t.Exception.InnerExceptions) else if (t.IsCanceled) tcs.TrySetCanceled(); else tcs.TrySetResult(t.Result); if (callback != null) callback(tcs.Task); }); return tcs.Task; }
  28. 28. Now, consider a case where we have a TAP implementation: public static Task<string> DownloadStringAsync(Uri url); And we need to provide an APM implementation: public IAsyncResult BeginDownloadString(Uri url, AsyncCallback callback, object state); public string EndDownloadString(IAsyncResult asyncResult);
  29. 29. This is achievable with the following code: public IAsyncResult BeginDownloadString( Uri url, AsyncCallback callback, object state) { return DownloadStringAsync(url).AsApm(callback, state); } public string EndDownloadString(IAsyncResult asyncResult) { return ((Task<string>)asyncResult).Result; }
  30. 30. The event-based asynchronous pattern relies on an instance MethodNameAsync method which returns void, accepts the same parameters as the synchronous MethodName method, and initiates the asynchronous operation. Prior to initiating the asynchronous operation, event handlers are registered with events on the same instance, and these events are then raised to provide progress and completion notifications. The event handlers are typically custom delegate types that utilize event argument types that are or that are derived from ProgressChangedEventArgs and AsyncCompletedEventArgs.
  31. 31. public static Task<string> DownloadStringAsync(Uri url) { var tcs = new TaskCompletionSource<string>(); var wc = new WebClient(); wc.DownloadStringCompleted += (s,e) => { if (e.Error != null) tcs.TrySetException(e.Error); else if (e.Cancelled) tcs.TrySetCanceled(); else tcs.TrySetResult(e.Result); }; wc.DownloadStringAsync(url); return tcs.Task; }
  32. 32. While not an asynchronous pattern per-se, advanced developers may find themselves utilizing WaitHandles and the ThreadPool’s RegisterWaitForSingleObject method to be notified asynchronously when a WaitHandle is set. We can wrap RegisterWaitForSingleObject to enable a task-based alternative to any synchronous wait on a WaitHandle:
  33. 33. public static Task WaitOneAsync(this WaitHandle waitHandle) { if (waitHandle == null) throw new ArgumentNullException("waitHandle"); var tcs = new TaskCompletionSource<bool>(); var rwh = ThreadPool.RegisterWaitForSingleObject(waitHandle, delegate { tcs.TrySetResult(true); }, null, -1, true); var t = tcs.Task; t.ContinueWith(_ => rwh.Unregister(null)); return t; }
  34. 34. The Task class implements IAsyncResult, and its IAsyncResult implementation exposes an AsyncWaitHandle property which returns a WaitHandle that will be set when the Task completes. As such, getting a WaitHandle for a Task is accomplished as follows: WaitHandle wh = ((IAsyncResult)task).AsyncWaitHandle;
  35. 35. We will create a WPF application to download a web page and find any link in the HTML. You will write the code in the old way by using synchronous calls and finally run the application to see the disadvantages of this way of programming
  36. 36. In this exercise, you will create a very simple application that will download the HTML content of a web page and, using regular expressions, search through that content looking for any link. Then, you will display those links in a ListBox. You will build this application in two ways. First, you will build the application using synchronous code and examine the issues with this implementation. Second, you will modify that application to use the asynchronous code so you can see how this implementation addresses the issues with the first version of the application.
  37. 37. try { var response = new HttpClient().Get(""); string result = response.EnsureSuccessStatusCode().Content.ReadAsString(); this.textBox1.Text = result; } catch (Exception) { MessageBox.Show(ex.ToString()); }
  38. 38. Notice the window is unresponsive and the button actually never disables because the UI is blocked while it downloads the web page.
  39. 39. In the previous code, you are using the asynchronous version of the Get method, the GetAsync, which is a new method added by the .NET Framework 4.5 and has different signature since it returns aTask type object. A task represents an asynchronous operation which may complete at some point in the future.
  40. 40. try { var response = new HttpClient().GetAsync(""); string result = response.EnsureSuccessStatusCode().Content.ReadAsStri ng(); this.textBox1.Text = result; ...
  41. 41. Adding the await keyword tells the compiler to asynchronously wait for the task returned from the method call. This means that the rest of the code will be executed as a callback only after the awaited method completes. Another thing to notice is that you do not need to change your try-catch block in order to make this work, as the exceptions that happen in the background or in the foreground will still be caught without any extra work using a handler provided by the framework.
  42. 42. try { var response = await new HttpClient().GetAsync(""); string result = response.EnsureSuccessStatusCode().Content.ReadAsStri ng(); this.textBox1.Text = result;
  43. 43. The await operator is applied to a task in an asynchronous method to suspend the execution of the method until the awaited task completes. The task represents ongoing work. The asynchronous method in which await is used must be modified by the async keyword. Such a method, defined by using the async modifier, and usually containing one or more await expressions, is referred to as an async method. The task to which the await operator is applied typically is the return value from a call to a method that implements the Task-Based Asynchronous Pattern. Examples include values of type Task or Task<TResult>.
  44. 44. An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off.
  45. 45. An await expression does not block the thread on which it is executing. Instead, it causes the compiler to sign up the rest of the async method as a continuation on the awaited task. Control then returns to the caller of the async method. When the task completes, it invokes its continuation, and execution of the async method resumes where it left off. An await expression can occur only in the body of an immediately enclosing method, lambda expression, or anonymous method that is marked by an async modifier. The term await serves as a contextual keyword only in that context. Elsewhere, it is interpreted as an identifier. Within the method, lambda expression, or anonymous method, an await expression cannot occur in the body of a synchronous function, in a query expression, in the catch or finally block of an exception handling statement, in the block of a lock statement, or in an unsafe context.
  46. 46. private async void button1_Click(object sender, EventArgs e) { // Call the method that runs asynchronously. string result = await WaitAsynchronouslyAsync(); // Call the method that runs synchronously. //string result = await WaitSynchronously (); // Display the result. textBox1.Text += result; }
  47. 47. // The following method runs asynchronously. The UI thread is not // blocked during the delay. You can move or resize the Form1 window // while Task.Delay is running. public async Task<string> WaitAsynchronouslyAsync() { await Task.Delay(10000); return "Finished"; } // The following method runs synchronously, despite the use of async. // You cannot move or resize the Form1 window while Thread.Sleep // is running because the UI thread is blocked. public async Task<string> WaitSynchronously() { // Add a using directive for System.Threading. Thread.Sleep(10000); return "Finished"; }
  48. 48. The async modifier indicates that the method, lambda expression, or anonymous method that it modifies is asynchronous. Such methods are referred to as async methods. An async method provides a convenient way to do potentially long-running work without blocking the caller's thread. The caller of an async method can resume its work without waiting for the async method to finish.
  49. 49. Typically, a method modified by the async keyword contains at least one await expression or statement. The method runs synchronously until it reaches the firstawait expression, at which point it is suspended until the awaited task is complete. In the meantime, control is returned to the caller of the method. If the method does not contain an await expression or statement, then it executes synchronously. A compiler warning alerts you to any async methods that do not contain await. The async keyword is a contextual keyword. It is a keyword when it modifies a method, a lambda expression, or an anonymous method. In all other contexts, it is interpreted as an identifier.
  50. 50. public async Task<int> ExampleMethodAsync() { // . . . // At the await expression, execution in this method is suspended and, // if AwaitedProcessAsync has not already finished, control returns // to the caller of ExampleMethodAsync. int exampleInt = await AwaitedProcessAsync(); // . . . // The return statement completes the task. Any method that is // awaiting ExampleMethodAsync can now get the integer result. return exampleInt; }
  51. 51. An async method can have a return type of void, Task, or Task<TResult>. The method cannot declare any ref or out parameters, although it can call methods that have such parameters. The void return type is used primarily to define event handlers, where a void return type is required. An async method that returns void cannot be awaited. In other cases, you specify Task<T> for the return type of an async method if the return statement of the method specifies an operand of type T. You use Task if no meaningful value is returned when the method is completed. You can think of the Task return type as meaning "Task<void>." That is, a call to the method returns a Task, but when the Task is completed, any await expression that is awaiting the Task evaluates to void.
  52. 52. // An event handler must return void. private async void button1_Click(object sender, RoutedEventArgs e) { textBox1.Clear(); // SumPageSizesAsync returns a Task. await SumPageSizesAsync(); textBox1.Text += "rnControl returned to button1_Click.rn"; }
  53. 53. // The following async lambda expression creates an equivalent anonymous // event handler. button1.Click += async (sender, e) => { textBox1.Clear(); // SumPageSizesAsync returns a Task. await SumPageSizesAsync(); textBox1.Text += "rnControl returned to button1_Click.rn"; }
  54. 54. // The following async method returns a Task<T>. private async Task<byte[]> GetByteArrayAsync(Uri currentURI) { // Declare an HttpClient object. HttpClient client = new HttpClient(); // The GetAsync method returns a Task(Of T), where T is an HttpResponseMessage. Task<HttpResponseMessage> httpRMTask = client.GetAsync(currentURI); // Await httpRMTask evaluates to an HttpResponseMessage object. HttpResponseMessage httpRM = await httpRMTask; // The following line can replace the previous two assignment statements. //HttpResponseMessage httpRM = await client.GetAsync(currentURI); // Throw an exception if the HttpResponseMessage contains an error code. httpRM.EnsureSuccessStatusCode(); // Use ReadAsByteArray to access the content of the resource as a byte array. return httpRM.Content.ReadAsByteArray(); }
  55. 55. Visual Studio 11 Developer Preview us/vstudio/hh127353 us/library/hh156513(v=vs.110).aspx