Category Archives: Eduasync

Eduasync part 6: using the infrastructure manually

Now that we’ve got the infrastructure for both returning a task from an async method, and awaiting a Task<T>, we’re going to look at what the compiler does for us. I always find that the best way of appreciating a feature like this is to consider what we’d have to do without it. Later on we’re going to see what the C# compiler does in terms of decompiling the actual generated code, but first we’ll look at what we might do to achieve the same end result, using the same infrastructure.

Of course, if we were doing all of this manually we might not choose to use the same infrastructure to start with, but I’m not sure that it would end up being much cleaner anyway.

A simple async method

First, let’s look at the C# 5 async method we want to emulate. It’s pretty simple:

private static async Task<int> ReturnValueAsyncWithAssistance()
{
    Task<int> task = Task<int>.Factory.StartNew(() => 5);

    return await task;
}

Now obviously we could just return the task here to start with – the async method isn’t providing any real benefit. But the simplicity is helpful for showing an equivalent. You can always imagine that there’s more going on between awaiting the result of the task and returning our actual result.

What do we need to do?

Before I include the actual code, let’s consider what we know about the async method execution model:

  • We’ll create an AsyncTaskMethodBuilder to allow us to return a Task<int>.
  • The method will start synchronously, running all the code before the first (and in this case only) await expression in the normal way.
  • The awaitable expression will be evaluated, and GetAwaiter() called to get a suitable awaiter value.
  • We’ll ask the awaiter whether the awaitable has already completed, using the IsCompleted property
    • If it’s already completed, we get the result by calling GetResult(). We can set the result on the builder, and return the builder’s task.
    • Otherwise, create a continuation delegate representing "the rest of the method". We then return the builder’s task.
      • The continuation has to fetch the result by calling GetResult() on the same awaiter, set the result on the builder, and return. (It’s not returning a Task<T> – the continuation is just an Action.)
  • If an exception occurs at any point, whether in the original synchronous call or the continuation, we need to set that exception in the builder, and return (either returning the builder’s task or nothing, depending on the context).

Even describing it makes it sound significantly worse than the async method. Let’s take a look.

Bring on the code!

Here’s the manual method in all its glory:

private static Task<int> ReturnValueAsyncWithoutAssistance()
{
    AsyncTaskMethodBuilder<int> builder = AsyncTaskMethodBuilder<int>.Create();

    try
    {
        Task<int> task = Task<int>.Factory.StartNew(() => 5);

        TaskAwaiter<int> awaiter = task.GetAwaiter();
        if (!awaiter.IsCompleted)
        {
            // Result wasn’t available. Add a continuation, and return the builder.
            awaiter.OnCompleted(() =>
            {
                try
                {
                    builder.SetResult(awaiter.GetResult());
                }
                catch (Exception e)
                {
                    builder.SetException(e);
                }
            });
            return builder.Task;
        }

        // Result was already available: proceed synchronously
        builder.SetResult(awaiter.GetResult());
    }
    catch (Exception e)
    {
        builder.SetException(e);
    }
    return builder.Task;
}

Ugly, isn’t it? Even so, it’s actually somewhere simpler than the real autogenerated code, which we’ll see in the next part. Hopefully if you read the code and comments bearing in mind the bullet points above, it should be reasonably easy to see how it works. However:

  • Currently we’re building a continuation delegate specific to this particular await. Imagine if we had several await expressions. Each would need "the rest of the method" specified as its own delegate, and we’d end up building multiple delegate instances over time.
  • It would be a nightmare to handle loops in this way.
  • We’ve got repeated code – not a lot in this case, but anything we had between the "await" and the "return" would need to be in both flows.
  • You don’t really want to be writing this code by hand anyway, if you can help it.

Having said all of that, it works. Just don’t expect me to write any more complicated async methods this way :)

Conclusion

The steps given here are still going to be valid with the compiler-generated code, but they’ll take a slightly different form. Next time we’ll decompile the generated code for the exact same async method, before we move on to look at more complicated cases.

Eduasync part 5: making Task awaitable

In part 3 we looked at what the C# 5 compiler required for you to "await" something. The sample used a class which actually had an instance method called GetAwaiter, but I mentioned that it could also be an extension method.

In this post, we’ll use that ability to make Task<T> awaitable – at which point we have everything we need to actually see some asynchronous behaviour. Just like the last part, the code here is pretty plain – but by the end of the post we’ll have a full demonstration of asynchrony. I should make it clear that this isn’t absolutely everything we’ll want, but it’s a good start.

TaskAwaiter<T>

As it happens, I’m using the same type name as the async CTP does for "something which can await a task" – TaskAwaiter. It’s in a different namespace though, and we could rename it with no ill-effects (unlike AsyncTaskMethodBuilder, for example). Indeed, in an old version of similar code I called this type Garçon – so GetAwaiter would return a waiter, so to speak. (Yes, you can use non-ASCII characters in identifiers in C#. I wouldn’t really advise it though.)

All the task awaiter needs is a reference to the task that it’s awaiting – it doesn’t need to know anything about the async method which is waiting for it, for example. Task<T> provides everything we need: a property to find out whether it’s completed, another to fetch the result, and the ContinueWith method to specify a continuation. The last part is particularly important – without that, we’d really have a hard time implementing this efficiently.

The extension method on Task<T> is trivial:

public static class TaskExtensions
{
    public static TaskAwaiter<T> GetAwaiter<T>(this Task<T> task)
    {
        return new TaskAwaiter<T>(task);
    }
}

The TaskAwaiter<T> type itself is slightly less so, but only slightly:

public struct TaskAwaiter<T>
{
    private readonly Task<T> task;

    internal TaskAwaiter(Task<T> task)
    {
        this.task = task;
    }

    public bool IsCompleted { get { return task.IsCompleted; } }

    public void OnCompleted(Action action)
    {
        SynchronizationContext context = SynchronizationContext.Current;
        TaskScheduler scheduler = context == null ? TaskScheduler.Current
            : TaskScheduler.FromCurrentSynchronizationContext();
        task.ContinueWith(ignored => action(), scheduler);
    }

    public T GetResult()
    {
        return task.Result;
    }
}

IsCompleted is obviously trivial – Task<T> provides us exactly what we need to know. It’s just worth noting that IsCompleted will return true if the task is cancelled, faulted or completed normally – it’s not the same as checking for success. However, it represents exactly what we want to know here.

OnCompleted has two very small aspects of interest:

  • ContinueWith takes an Action<Task<T>> or an Action<Task>, not just an Action. That means we have to create a new delegate to wrap the original continuation. I can’t currently think of any way round this with the current specification, but it’s slightly annoying. If the compiler could work with an OnCompleted(Action<object>) method then we could pass that into Task<T>.ContinueWith due to contravariance of Action<T>. The compiler could generate an appropriate MoveNext(object) method which just called MoveNext() and stash an Action<object> field instead of an Action field… and do so only if the async method actually required it. I’ll email the team with this as a suggestion – they’ve made other changes with performance in mind, so this is a possibility. Other alternatives:
    • In .NET 5, Task<T> could have ContinueWith overloads accepting Action as a continuation. That would be simpler from the language perspective, but the overload list would become pretty huge.
    • I would expect Task<T> to have a "real" GetAwaiter method in .NET 5 rather than the extension method; it could quite easily just return "this", possibly with some explicitly implemented IAwaiter<T> interface to avoid polluting the normal API. That could then handle the situation more natively.
  • We’re using the current synchronization context if there is one to schedule the new task. This is the bit that lets continuations keep going on the UI thread for WPF and WinForms apps. If there isn’t a synchronization context, we just use the current scheduler. For months this was incorrect in Eduasync; I was using TaskScheduler.Current in all cases. It’s a subtle difference which has a huge effect on correctness; apologies for the previous inaccuracy. Even the current code is a lot cruder than it could be, but it should be better than it was…

GetResult looks and is utterly trivial – it works fine for success cases, but it doesn’t do what we really want if the task has been faulted or cancelled. We’ll improve it in a later part.

Let’s see it in action!

Between this and the AsyncTaskMethodBuilder we wrote last time, we’re ready to see an end-to-end asynchronous method demo. Here’s the full code – it’s not as trivial as it might be, as I’ve included some diagnostics so we can see what’s going on:

internal class Program
{
    private static readonly DateTimeOffset StartTime = DateTimeOffset.UtcNow;

    private static void Main(string[] args)
    {
        Log("In Main, before SumAsync call");
        Task<int> task = SumAsync();
        Log("In Main, after SumAsync returned");

        int result = task.Result;
        Log("Final result: " + result);
    }

    private static async Task<int> SumAsync()
    {
        Task<int> task1 = Task.Factory.StartNew(() => { Thread.Sleep(500); return 10; });
        Task<int> task2 = Task.Factory.StartNew(() => { Thread.Sleep(750); return 5; });

        Log("In SumAsync, before awaits");
           
        int value1 = await task1;
        int value2 = await task2;

        Log("In SumAsync, after awaits");

        return value1 + value2;
    }

    private static void Log(string text)
    {
        Console.WriteLine("Thread={0}. Time={1}ms. Message={2}",
                          Thread.CurrentThread.ManagedThreadId,
                          (long)(DateTimeOffset.UtcNow – StartTime).TotalMilliseconds,
                          text);
    }
}

And here’s the result of one run:

Thread=1. Time=12ms. Message=In Main, before SumAsync call
Thread=1. Time=51ms. Message=In SumAsync, before awaits
Thread=1. Time=55ms. Message=In Main, after SumAsync returned
Thread=4. Time=802ms. Message=In SumAsync, after awaits
Thread=1. Time=802ms. Message=Final result: 15

So what’s going on?

  • We initially log before we even start the async method. We can see that the thread running Main has ID 1.
  • Within SumAsync, we start two tasks using Task.Factory.StartNew. Each task just has to sleep for a bit, then return a value. Everything’s hard-coded.
  • We log before we await anything: this occurs still on thread 1, because async methods run synchronously at least as far as the first await.
  • We hit the first await, and because the first task hasn’t completed yet, we register a continuation on it, and immediately return to Main.
  • We log that we’re in Main, still in thread 1.
  • When the first await completes, a thread from the thread pool will execute the continuation. (This may well be the thread which executed the first task; I don’t know the behaviour of the task scheduler used in console apps off the top of my head.) This will then hit the second await, which also won’t have finished – so the first continuation completes, having registered a second continuation, this time on the second task. If we changed the Sleep calls within the tasks, we could observe this second await actually not needing to wait for anything.
  • When the second continuation fires, we log that fact. Two things to notice:
    • It’s almost exactly 750ms after the earlier log messages. That proves that the two tasks has genuinely been executing in parallel.
    • It’s on thread 4.
  • The final log statement occurs immediately after we return from the async method – thread 1 has been blocked on the task.Result property fetch, but when the async method completes, it unblocks and shows the result.

I think you’ll agree that for the very small amount of code we’ve had to write, this is pretty nifty.

Conclusion

We’ve now implemented enough of the functionality which is usually in AsyncCtpLibrary.dll to investigate what the compiler’s really doing for us. Next time I’ll include a program showing one option for using the same types within hand-written code… and point out how nasty it is. Then for the next few parts, we’ll look at what the C# 5 compiler does when we let it loose on code like the above… and show why I didn’t just have "int value = await task1 + await task2;" in the sample program.

If you’ve skimmed through this post reasonably quickly, now would be a good time to go back and make sure you’re really comfortable with where in this sample our AsyncTaskMethodBuilder is being used, and where TaskAwaiter is being used. We’ve got Task<T> as the core type at both boundaries, but that’s slightly coincidental – the boundaries are still very different, and it’s worth making sure you understand them before you try to wrap your head round the compiler-generated code.

Eduasync part 4: Filling in AsyncTaskMethodBuilder

In part 2, I introduced AsyncVoidMethodBuilder, AsyncTaskMethodBuilder and AsyncTaskMethodBuilder<T>. I showed all the signatures, but the implementations were basically trivial and non-functional. Today, I’m going to change all of that… at least a bit.

In particular, by the end of this post we’ll be able to make the following code actually print out 10 as we’d expect:

private static void Main(string[] args)
{
    Task<int> task = Return10Async();
    Console.WriteLine(task.Result);
}

private static async Task<int> Return10Async()
{
    return 10;
}

Note that there are no await statements – remember that AsyncTaskMethodBuilder<T> is about the boundary between the caller and the async method. We won’t be actually doing anything genuinely asynchronous today – just filling in a piece of the infrastructure.

I’m not going to implement AsyncVoidMethodBuilder or AsyncTaskMethodBuilder, because once you understand how AsyncTaskMethodBuilder<T> works, the others are basically trivial to implement. (Certainly the non-generic AsyncTaskMethodBuilder is too similar to warrant going into; I may potentially revisit AsyncVoidMethodBuilder to investigate its behaviour on exceptions.)

Just as a reminder, this is what we need our AsyncTaskMethodBuilder<T> struct to look like in terms of its interface:

public struct AsyncTaskMethodBuilder<T>
{
    public static AsyncTaskMethodBuilder<T> Create();
    public void SetException(Exception e);
    public void SetResult(T result);
    public Task<T> Task { get; }
}

Frankly, this would be a bit of a pain to implement ourselves… especially if we wanted to do it in a neat way which didn’t introduce a new thread unnecessarily. Fortunately, Parallel Extensions makes it pretty easy.

TaskCompletionSource to the rescue!

The TaskCompletionSource<TResult> type in the framework makes it almost trivial to implement AsyncTaskMethodBuilder<T>. It provides us everything we need – a task, and the ability to specify how it completes, either with an exception or a value. Our initial implementation is really just going to wrap TaskCompletionSource. I suspect the real CTP does slightly more work, but you can get a remarkably long way with simple wrapping:

public struct AsyncTaskMethodBuilder<T>
{
    private readonly TaskCompletionSource<T> source;

    private AsyncTaskMethodBuilder(TaskCompletionSource<T> source)
    {
        this.source = source;
    }

    public static AsyncTaskMethodBuilder<T> Create()
    {
        return new AsyncTaskMethodBuilder<T>(new TaskCompletionSource<T>());
    }

    public void SetException(Exception e)
    {
        source.SetException(e);
    }

    public void SetResult(T result)
    {
        source.SetResult(result);
    }

    public Task<T> Task { get { return source.Task; } }
}

We’ll see how far that takes us – we may need to tweak it a bit, probably around the exception handling. For the moment though, it certainly does everything we need it to. The program runs, and prints out 10 as we’d expect.

This part of the code is now ready for asynchrony – even though nothing we’ve done so far actually creates any different threads. If we call SetResult from one thread while another thread is waiting on the task’s result, the waiting thread will be unblocked as we’d expect.

Conclusion

In some ways I hope you’re disappointed by this, in the same way that looking at the LINQ to Objects implementations can be slightly disappointing. It feels like so much is being given to us for free – the framework already had all this power, so what’s C# 5 really adding to the mix. Well, we’re nearly at the point where I can show you the details of what the compiler’s doing under the hood. That’s where the real power lies, and is why I’m so excited by the feature.

First though, we need to implement the awaiter pattern for Task<T>. That’s the task of our next post, and then we can complete the picture by decompiling the generated code for some programs using genuine asynchrony.

Eduasync part 3: the shape of the async method / awaitable boundary

Last time we looked into the boundary between the caller of an async method and the method itself.

This time I’m going to show the same sort of "skeleton API" but for awaitable types. This is at the heart of C# 5’s async feature: within an async method, you can include "await" expressions. You have to await a value – which could be the return value from a method call, or a property, or the value of a variable. The important thing is that the compile-time type of that expression has the right shape.

Definition time

Consider this code snippet from an async method (separated into two statements for clarity):

Task<string> t = new WebClient().DownloadStringTaskAsync(url);
string text = await t;

I wish to define the following terms:

  • The task of the await expression is the expression which comes after "await"; in this case it’s just "t".
  • The awaitable type is the compile-time type of the task. In this case it’s Task<string>.
  • The awaiter type is the compile-time type of the result of calling GetAwaiter() on the task.
  • The result type is the compile-time return type of the awaiter type’s GetResult method. Here it would be string, when using the CTP or any sensible implementation.

(Of these, "task" and "awaiter type" are part of the draft specification. "Awaitable type" and "result type" aren’t.)

Now, the first two are fairly clear from the code above, but the awaiter and result types aren’t. The compiler validates that calling (foo).GetAwaiter() for a task expression "foo" is valid. It doesn’t have to be an instance method – it can be an extension method, and indeed that’s how it’s implemented in the CTP. Unlike the weird things you can do with LINQ query expressions, GetAwaiter() really does have to be a method call, and the expression can’t just be a type name. Unless you’re trying to do weird stuff, this is very unlikely to be an issue for you. It’s only oddballs like me who try to push the envelope.

With the current CTP the awaitable type can’t be "dynamic", but the aim is for C# 5 to support awaiting dynamic values. I imagine this won’t affect the execution flow significantly though.

The awaitable type only has to support the GetAwaiter() method, as we’ve said. The awaiter type has to have the following accessible members (which can’t be extension methods):

  • bool IsCompleted { get; }
  • void OnCompleted(Action continuation)
  • X GetResult() where X defines the result type for the awaiter, and may be void

The overall type of the await expression is the result type – and it has to be appropriate for any surrounding context. For example, the assignment to the "text" variable will only work in our sample if the result type is "string" or a type with an implicit conversion to string.

A simple (non-functional) awaiter

The sample code for this post comes from project 5 in the source solution (SimpleInt32Awaitable); project 4 is similar but with a void result type. Neither project makes any attempt to do any real awaiting:

// Within some other class
static async void SimpleWaitAsync()
{
    SimpleInt32Awaitable awaitable = new SimpleInt32Awaitable();
    int result = await awaitable;
}
 

public struct SimpleInt32Awaitable
{
    public SimpleInt32Awaiter GetAwaiter()
    {
        return new SimpleInt32Awaiter();
    }
}

public struct SimpleInt32Awaiter
{
    public bool IsCompleted { get { return true; } }

    public void OnCompleted(Action continuation)
    {
    }

    public int GetResult()
    {
        return 5;
    }
}

Note that here both the awaitable type and the awaiter type are structs rather than classes; this is not a requirement by any means.

What does it all mean?

I don’t want to leave this post without any clue of what all of this is used for.

Fairly obviously, GetAwaiter() is called to get an awaiter (clever name, huh?) on which some members are called:

  • IsCompleted is called to determine whether the task has already completed. If it has, we can skip over the next step.
  • If the task hasn’t already completed, we want to return very soon rather than waiting – so OnCompleted is calling with a delegate representing the continuation of the method. The awaiter promises to ensure that the continuation is called when (and only when) the task has completed, possibly with an exception.
  • When we know the task has completed (either synchronously or via the continuation), GetResult is called to retrieve the result. Note that even if the method has a void return type, it still has to be called, as the "result" may be that an exception is thrown.

Conclusion

Awaiters are pretty flexible – which means they can be abused in evil, horrible ways, as we’ll see later on.

So far we’ve seen the basic shape of both boundaries, and now we can start actually implementing them with real, useful code.

Eduasync part 2: the shape of the caller / async method boundary

For the first few parts of this blog series, we’re not going to write code which actually does anything useful. We’re looking at the API more than the implementation – the bare necessities to get the code to compile. Remember that we’re working without AsyncCtpLibrary.dll – which of course supplies all the necessary types normally.

In this part, we’ll look at the boundary between the caller and the async method itself. Our test code will have a method which does nothing but return – but which is marked with the “async” modifier. The fact that we don’t have an “await” expression in the method causes a compiler warning – which is entirely reasonable, but irrelevant to our particular situation.

Three return types, one basic idea

Async methods are limited to three different return types:

  • void
  • Task (non-generic)
  • Task<T> (generic for any type T)

Each of these return types needs a very slightly different form of compiler support… but the general principle is the same. I’ll show each of the three different types, but the test code itself remains exactly the same except for the return type of the method and the return statement. (If you’re going to return Task<int>, you need to return an int, etc.)

namespace Eduasync
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            DoNothingAsync();
        }

// Warning CS1998 is about a method with no awaits in… exactly what we’re trying to
// achieve!
#pragma warning disable 1998 
        // Return type of void, Task or Task<int>
        private static async void DoNothingAsync()
        {
            // For Task<int> insert return 0; here
        }
#pragma warning restore 1998
    }
}

If you try to compile this code without anything else, the compiler gives an error like this:

Test.cs(14,30): error CS0656: Missing compiler required member ‘System.Runtime.CompilerServices.AsyncVoidMethodBuilder.Create’
Test.cs(14,30): error CS1993: Cannot find Task-related types. Are you missing a reference to ‘AsyncCtpLibrary.dll’ ?

While you’d get a similar error for the async method / awaitable boundary, this one is more demanding: you have to have exactly the right types available. It isn’t just a matter of any library providing support for your current situation (in the same way that Edulinq can live in its own namespace and be an alternative for LINQ to Objects without the compiler caring). These are exact types that the compiler relies on. They’re an implementation detail: they can vary between compilers (so Mono could have a different set of types for example, although I doubt that it will, for the sake of binary compatibility) and they’re not part of the language specification… at least at the moment.

There are three types required: AsyncVoidMethodBuilder, AsyncTaskMethodBuilder and AsyncTaskMethodBuilder<T>. They correspond (fairly obviously) to the return types of void, Task, and Task<T> respectively.

They all look largely the same, but here are my initial "non-implementations":

using System.Threading.Tasks;

namespace System.Runtime.CompilerServices
{
    public struct AsyncVoidMethodBuilder
    {
        public static AsyncVoidMethodBuilder Create()
        {
            return new AsyncVoidMethodBuilder();
        }

        public void SetException(Exception e) {}
        public void SetResult() {}
    }

    public struct AsyncTaskMethodBuilder
    {
        public static AsyncTaskMethodBuilder Create()
        {
            return new AsyncTaskMethodBuilder();
        }

        public void SetException(Exception e) {}
        public void SetResult() {}
        public Task Task { get { return null; } }
    }

    public struct AsyncTaskMethodBuilder<T>
    {
        public static AsyncTaskMethodBuilder<T> Create()
        {
            return new AsyncTaskMethodBuilder<T>();
        }

        public void SetException(Exception e) {}
        public void SetResult(T result) {}
        public Task<T> Task { get { return null; } }
    }
}

(In the Eduasync project these are in separate files and have diagnostic statements in the SetException/SetResult methods. I didn’t want to take up too much space here.)

Note that these must be structs. If they’re not, the compiler will complain. All the methods have to have the exact signatures specified, as far as I can tell – except that everything can be internal if you want it to be (so long as your async methods are in the same assembly of course). In practice these are going to be public, and they are public everywhere in Eduasync.

With these implementations, you can compile and even run async methods – but you will, of course, end up with a null reference returned from any async method with a return type of Task or Task<T>.

In case you’re wondering, the code below shows a little taste of how these types are used. It’s from the version of DoNothingAsync which returns a non-generic Task. This is what the compiler replaces our code with:

private static Task DoNothingAsync()

    <DoNothingAsync>d__0 d__ = new <DoNothingAsync>d__0(0);
    d__.<>t__MoveNextDelegate = new Action(d__.MoveNext);
    d__.$builder = AsyncTaskMethodBuilder.Create();
    d__.MoveNext(); 
    return d__.$builder.Task; 
}

Obviously <DoNothingAsync>d__0 is a compiler-generated type (hence the unspeakable name). I’m not going into the details just yet – that will the topic of several posts in a little while. The main point of this post was just to show you the shape of what the compiler requires. The Create() method and the Task property are used within the rewritten method; the SetResult() and SetException() methods are used within the generated type (the state machine) to indicate the async method completing.

Before too long we’ll implement these types properly (which is reasonably straightforward, given help from the BCL).

Conclusion

The caller / async method boundary is relatively inflexible. The compiler relies on particular types, and you simply can’t make an async method return a different kind of value, such as your own Future<T> type. The guts of how it works are all hidden from you, unless you try to compile without the right libraries around: while the valid return types are part of the specification, the types used by the compiler aren’t. While this is perhaps a little unfortunate in a purist sense, it’s not really a big deal. The "consuming" part of the async method (the boundary between the async method and whatever it’s awaiting) is much more flexible, and more interesting. That’s what we’re going to look at next.

Eduasync part 1: introduction

I’ve been waiting to start this blog series for a couple of months. It’s nice to finally get cracking.

Hopefully some of you have already read some of my thoughts around C# 5’s async feature, mostly written last year. Since that initial flurry of posts, I’ve been pretty quiet, but I’m still really excited about it. Really, really excited. I’ve given a few talks on it, and I have a few more still to give – and this blog series will partly be complementary to those talks. In particular, there’s a DevExpress webcast which covers most of the same ground, with similar code. (It was before the CTP refresh, and also before my laptop was stolen in a burglary, so the code here is a rewrite.)

Async from a compiler’s point of view

Most of this blog series (at least the bits I anticipate at the moment) will deal with what the compiler does with async methods. (I haven’t used async delegates much at all, but I can’t imagine that the machinery is particularly different.)

As far as I’ve seen, most of the coverage on the web so far has dealt with using async. That’s natural, logical and entirely proper. Oh, and a bit boring after a while. I like knowing how a feature works before I go too far using it. This is a personal idiosyncrasy, and if you’re happy just using async with no “under the hood” details, that’s absolutely fine. It’s probably worth unsubscribing from my blog for a little while, that’s all.

This can all be seen as pretty similar to my Edulinq series of posts, which is why I’ve called it Eduasync this time.

My plan is to walk you through what the C# compiler relies on – the types which are currently part of AsyncCtpLibrary.dll, and how it interacts with Task / Task from .NET 4. We’ll then look at the code generated by the compiler – essentially a state machine – and some of the less obvious aspects of it. I’ll give examples of any bugs I’ve found in the CTP, just for the heck of it – and as a way of checking whether they’re fixed in later versions. (Obviously I’ve let the C#/VB team know about these as I’ve come across them.)

I’ll assume that you know the basics of using async – so if you don’t, now would be a good time to look at the numerous resources on the Visual Studio Async home page. There are loads of videos, specs (including the C# spec changes, most importantly from my point of view)

Get the source now

There’s already quite a bit of source code (everything I’m currently planning on writing about, which is almost inevitably less than I’ll actually end up writing about) on the Google Code Eduasync project. This takes a different approach from Edulinq – instead of just a couple of projects (production and tests, basically) I’ve got a separate project for each topic I want to talk about, with pretty minimal code for that topic. The reason for this is to show the evolution of the code – starting off with almost nothing, and progressing until we’ve got an implementation which achieves at least the bare bones important bits of an async system.

I’ve numbered the projects within the solution, although the assemblies themselves don’t have the same numbers. They all use a default namespace of just Eduasync, and they don’t refer to each other. Each is meant to be self-contained – oh, and there are no references to AsyncCtpLibrary.dll. The whole point is to reimplement that library :) Of course, you’ll still need the CTP installed to get the compiler changes.

The Google Code repository will also contain the blog posts eventually, including any diagrams I need to create (such as the one in a minute).

The three blocks and two boundaries

One of the things I’ve found important to think about in async is the various parts involved. I’ve ended up with a mental model like this:

The bits in blue and red are the ones we’re focusing on here: the contents of the async method, and the boundaries between that and the code that calls it, and the tasks (or other awaitable types) that it awaits.

For most of this series we’re not really going to care much about what the caller does with the result, or how the awaitable object behaves other than in terms of the methods and properties used by the C# 5 compiler. I’ll discuss the flexibility afforded though – and how it doesn’t extend to the “caller/async” boundary, only the “async/awaitable” boundary.

Just to give an explicit example of all of this, here’s a simple little program to asynchronously determine the size of the Stack Overflow home page:

using System;
using System.Net;
using System.Threading.Tasks;

class Program
{
    // Caller (block 1)
    static void Main()
    {
        Task<int> sizeTask = DownloadSizeAsync(http://stackoverflow.com&#8221;);
        Console.WriteLine(“In Main, after async method call…”);        
        Console.WriteLine(“Size: {0}”, sizeTask.Result);
    }
    
    // Async method (block 2)
    static async Task<int> DownloadSizeAsync(string url)
    {
        var client = new WebClient();
        // Awaitable (block 3)
        var awaitable = client.DownloadDataTaskAsync(url);
        
        Console.WriteLine(“Starting await…”);
        byte[] data = await awaitable;
        Console.WriteLine(“Finished awaiting…”);
        
        return data.Length;
    }
}

The comments should make it reasonably clear what the blocks in the diagram mean. It’s not ideal in that the first two blocks are basically methods, whereas the third block is an object – but I’ve found that it still makes sense when we’re thinking about the interactions involved at the boundaries. Notably:

  • How does the async method create an appropriate value to return to the caller?
  • How does the async method interact with the awaitable when it hits an “await” expression?

We can (and we’re going to) look at these boundaries very separately. We’ll start off with the first bullet, in part two, which will hopefully follow in the next few days.