More on Async Functions

In my last post I showed .Net 1.1 and .NET 2.0 code that performed some asychronous operations.  I then showed the new syntax with “async” and “await” that did the same thing.


But, I didn’t detail what’s really going on in the new syntax.


If you want to know more about the details of what’s going on, read on.  If you just trust me about the previous code, you don’t have to read on :)


When the Click handler is executed it basically executes everything up to the first await and returns.  This allows the UI to be responsive.  The compiler generates some code that takes the Task<T> object that is returned from the async method and waits for it.  If there is code that needs to execute after the await, then the compiler effectively generates a continuation.  With regard to Task<T>, that’s basically a call to Task<T>.ContinueWith.  Any other await statements are collected in that continuation and the same thing is done, the continuation is executed up to the first await and returns…


The underlying architecture knows about synchronization contexts and makes sure “synchronous” code within the Click handler is executed on the UI thread.  So, as you saw in the example, we didn’t have to manually deal with marshaling back to the UI thread via Control.Invoke().


My original example was overly simplistic and didn’t include anything to deal with disposal.  To a certain extent I’ve done async functions a disservice because async functions make disposal much, much easier.  For example, my .NET 4.0 code would do something like this:


private void button_Click(object sender, EventArgs e)
{
 button.Enabled = false;
 var webRequest = WebRequest.Create(“
http://google.ca“);
 webRequest.BeginGetResponse(asyncResult =>
 {
  var response = webRequest.EndGetResponse(asyncResult);
  var stream = response.GetResponseStream();
  if (stream != null)
  {
   var reader = new StreamReader(stream);
   var text = reader.ReadToEnd();
   BeginInvoke((MethodInvoker) (() =>
   {
    textBox.Text = text;
    button.Enabled = true;
    reader.Dispose();
    stream.Dispose();
    ((IDisposable) response).Dispose();
   }));
  }
  else
  {
   ((IDisposable)response).Dispose();
  }
 }, null);
}


As you can see, we can’t use the using statement because that assumes the block in which using block resides is run asynchronously, so we’re forced to manually call Dispose (and in the case of WebResponse, cast to IDisposable first because it explicitly implements IDisposable).


With await, we can write a block of code with bits of it being asynchronous and still use using statements.  So, with async functions, our code can now dispose more cleanly; for example:


private async void button1_Click(object sender, EventArgs e)
{
 try
 {
  button.Enabled = false;
  var webRequest = WebRequest.Create(“
http://google.ca“);
  using (var response = await webRequest.GetResponseAsync())
  using (var stream = response.GetResponseStream())
  {
   if (stream == null) return;
   using (var reader = new StreamReader(stream))
   {
    textBox.Text = await reader.ReadToEndAsync();
   }
  }
 }
 finally
 {
  button.Enabled = true;
 }
}


C# 3 and lambda expressions make the act of using asynchronous methods much easier than .NET 1.x; the next version of C# with async functions takes it that final step forward.

A New Asynchronicity Awaits You

The languages team at Microsoft have just announced that both VB and C# are giving first-class citizenship to asynchronous operations.


At long last we can cleanly program for asynchronous operations without cluttering up the code with imperative artefacts relating to how the asynchronous operation is being performed.


Let’s have a quick look at how we had you might perform an asynchronous operation in .NET 1.x:


	byte[] readbuffer = new byte[1024];

public void Button1_Click()
{
WebRequest webRequest = WebRequest.Create("http://msdn.com");
webRequest.BeginGetResponse(new AsyncCallback(BeginGetResponseCallback), webRequest);
}

private void BeginGetResponseCallback(IAsyncResult asyncResult)
{
WebRequest webRequest = (WebRequest)asyncResult.AsyncState;
WebResponse webResponse = webRequest.EndGetResponse(asyncResult);

Stream stream = webResponse.GetResponseStream();
stream.BeginRead(readbuffer, 0, readbuffer.Length, new AsyncCallback(BeginReadCallback), stream);
}

private delegate void TakeString(string text);

private void BeginReadCallback(IAsyncResult asyncResult)
{
Stream stream = (Stream)asyncResult.AsyncState;
int read = stream.EndRead(asyncResult);
this.Invoke(new TakeString(SetTextBoxText), new object[] {Encoding.ASCII.GetString(readbuffer, 0, read);
}

private void SetTextBoxText(String text)
{
textBox.Text = text;
}

In .NET 1.x, in order to go get data from a web page in response to a button click, we had to create two methods that acted as callback for the asynchronous get web request and asynchronous read response.  As well, we had to create a method to marshal data back to the UI thread via Control.Invoke so that modification of controls (setting of Text property) is done only on the UI thread.


 


In .NET 2.0 this got much easier.  We could use anonymous methods and get rid of our callback methods altogether to get something like this:


	public void Button1_Click(object snder, EventArgs e)
{
WebRequest webRequest = WebRequest.Create("http://msdn.com");
webRequest.BeginGetResponse(delegate(IAsyncResult asyncResult)
{
WebRequest webRequest1 = (WebRequest) asyncResult.AsyncState;
WebResponse webResponse = webRequest1.EndGetResponse(asyncResult);

Stream stream = webResponse.GetResponseStream();
stream.BeginRead(readbuffer, 0, readbuffer.Length, asyncResult1 =>
         {
             Stream stream1 =
                 (Stream) asyncResult1.AsyncState;
             int read =
                 stream1.EndRead(asyncResult1);
             this.Invoke(
                 new TakeString(
                     delegate(string text)
                         {
                             textBox.Text =
                              Encoding.ASCII.GetString(
                              stream1, 0, read);
                         }));
         }, stream);
}, webRequest);
}

But, the details of anonymous methods and closures really make this code complex and hard to understand.


In some future version of VB and C#, it will become even easier with the new await/Await and async/Async keywords.  In conjunction with the Task Parallel Library, you will now capable of declaring an asynchronous method (“asynch”) and inform the compiler which part of the method is asynchronous (“await”).  For example:


	private async void Button1_Click(object sender, EventArgs e)
{
var request = WebRequest.Create("http://msdn.com");
var response = await request.GetResponseAsync();
var reader = new StreamReader(response.GetResponseStream());

textBox.Text = await
reader.ReadToEndAsync();
}


Much, much simpler and easier to read.  “async” tells the compiler that a method uses the await keyword.  The await keyword tells the compiler that the method being called returns some sort of Task<> object, the type parameter signifying the left-hand-side type of the method call and that the method uses the Task Parallel library to spin up that Task<> object to perform the operation asynchronously.


As you might imagine, there’s a plethora of new methods in the BCL that will now return a Task<> object (and have the postfix of “Async”) that can be used with the await keyword.