Category Archives: async

C# 5 async: experimenting with member resolution (GetAwaiter, BeginAwait, EndAwait)

Some of you may remember the bizarre query expressions I’ve come up with before now. These rely on LINQ finding the members it needs (Select, Where, SelectMany etc) statically but without relying on any particular interface. I was pleased to see that the C# 5 async support is based on the same idea. Here’s the relevant bit of the draft spec:

The expression t of an await-expression await t is called the task of the await expression. The task t is required to be awaitable, which means that all of the following must hold:

  • (t).GetAwaiter() is a valid expression of type A.
  • Given an expression a of type A and an expression r of type System.Action, (a).BeginAwait(r) is a valid boolean-expression.
  • Given an expression a of type A, (a).EndAwait() is a valid expression.

A is called the awaiter type for the await expression. The GetAwaiter method is used to obtain an awaiter for the task.

The BeginAwait method is used to sign up a continuation on the awaited task. The continuation passed is the resumption delegate, which is further explained below.

The EndAwait method is used to obtain the outcome of the task once it is complete.

The method calls will be resolved syntactically, so all of GetAwaiter, BeginAwait and EndAwait can be either instance members or extension methods, or even bound dynamically, as long as the calls are valid in the context where the await expression appears. All of them are intended to be “non-blocking”; that is, not cause the calling thread to wait for a significant amount of time, e.g. for an operation to complete.

As far as I can tell, either the CTP release hasn’t fully implemented this, or I’ve interpreted a bit overly broadly. Still, let’s see what works and what doesn’t. For simplicity, each example is completely self-contained… and does absolutely nothing interesting. It’s only the resolution part which is interesting. (The fact that the Main method is async is quite amusing though, and takes advantage of the fact that async methods can return void instead of a task.)

Example 1: Boring instance members

This is closest to the examples I’ve given so far.

using System;

class Test
{
    static async void Main()
    {
        await new Awaitable();
    }
}

class Awaitable
{
    public Awaiter GetAwaiter()
    {
        return new Awaiter();
    }    
}

class Awaiter
{
    public bool BeginAwait(Action continuation)
    {
        return false;
    }
    
    public int EndAwait()
    {
        return 1;
    }
}

Hopefully this needs no further explanation. Obviously it works fine with the CTP. The compiler generates a call to GetAwaiter, then calls BeginAwait and EndAwait on the returned Awaiter.

Example 2: Extension methods

The CTP uses extension methods to get an awaiter for existing types such as Task – but I don’t think it uses them for BeginAwait/EndAwait. Fortunately, there’s nothing to stop us from using them for everything, and there’s nothing forcing you to put the extension methods on sensible types, either – as demonstrated below:

using System;

class Test
{
    static async void Main()
    {
        Guid guid = await 5;
        Console.WriteLine("Got result: {0}", guid);
    }
}

static class Extensions
{
    public static string GetAwaiter(this int number)
    {
        return number.ToString();
    }
    
    public static bool BeginAwait(this string text, Action continuation)
    {
        Console.WriteLine("Waiting for {0} to finish", text);
        return false;
    }
    
    public static Guid EndAwait(this string text)
    {
        Console.WriteLine("Finished waiting for {0}", text);
        return Guid.NewGuid();
    }
}

I should just emphasize that this code is purely for the sake of experimentation. If I ever see anyone actually extending int and string in this way in production code and blaming me for giving them the idea, I’ll be very cross.

However, it all does actually work. This example is silly but not particularly exotic. Let’s start going a bit further, using dynamic typing.

Example 3: Dynamic resolution

The spec explicitly says that the methods can be bound dynamically, so I’d expect this to work:

using System;
using System.Dynamic;

class Test
{
    static async void Main()
    {
        dynamic d = new ExpandoObject();
        d.GetAwaiter = (Func<dynamic>) (() => d);
        d.BeginAwait = (Func<Action, bool>) (action => {
            Console.WriteLine("Awaiting");
            return false;
        });
        d.EndAwait = (Func<string>)(() => "Finished dynamically");

        string result = await d;
        Console.WriteLine("Result: {0}", result);
    }
}

Unfortunately, in the CTP this doesn’t work – it fails at compile time with this error:

Test.cs(16,25): error CS1991: Cannot await ‘dynamic’

All is not lost, however. We may not be able to make GetAwaiter to be called dynamically, but what about BeginAwait/EndAwait? Let’s try again:

using System;
using System.Dynamic;

class DynamicAwaitable
{
    public dynamic GetAwaiter()
    {
        dynamic d = new ExpandoObject();
        d.BeginAwait = (Func<Action, bool>) (action => {
            Console.WriteLine("Awaiting");
            return false;
        });
        d.EndAwait = (Func<string>)(() => "Finished dynamically");
        return d;
    }
}

class Test
{
    static async void Main()
    {
        string result = await new DynamicAwaitable();
        Console.WriteLine("Result: {0}", result);
    }
}

This time we get more errors:

Test.cs(22,25): error CS1061: ‘dynamic’ does not contain a definition for ‘BeginAwait’ and no extension method ‘BeginAwait’ accepting a first argument of type ‘dynamic’ could be found (are you missing a using directive or an assembly reference?)

Test.cs(22,25): error CS1061: ‘dynamic’ does not contain a definition for ‘EndAwait’ and no extension method ‘EndAwait’ accepting a first argument of type ‘dynamic’ could be found (are you missing a using directive or an assembly reference?)

Test.cs(22,25): error CS1986: The ‘await’ operator requires that its operand ‘DynamicAwaitable’ have a suitable public GetAwaiter method

This is actually worse than before: not only is it not working as I’d expect to, but even the error message has a bug. The await operator doesn’t require that its operand has a suitable public GetAwaiter method – it just has to be accessible. At least, that’s the case with the current CTP. In my control flow post for example, the methods were all internal. It’s possible that the error message is by design, and the compiler shouldn’t have allowed that code, of course – but it would seem a little odd.

Okay, so dynamic resolution doesn’t work. Oh well… let’s go back to static typing, but use delegates, fields and properties.

Example 4: Fields and properties of delegate types

This time we’re back to the style of my original "odd query expressions" post, using fields and properties returning delegates instead of methods:

using System;

class FieldAwaiter
{
    public readonly Func<Action, bool> BeginAwait = continuation => false;
    public readonly Func<string> EndAwait = () => "Result from a property";
}

class PropertyAwaitable
{
    public Func<FieldAwaiter> GetAwaiter
    {
        get { return () => new FieldAwaiter(); }
    }
}

class Test
{
    static async void Main()
    {
        string result = await new PropertyAwaitable();
        Console.WriteLine("Result: {0}", result);
    }
}

Again, I believe this should work according to the spec. After all, this block of code compiles with no problems:

var t = new PropertyAwaitable();
var a = (t).GetAwaiter();
bool sync = (a).BeginAwait(() => {});
string result = (a).EndAwait();

Unfortunately, nothing doing. The version using await fails with this error:

Test.cs(21,25): error CS1061: ‘PropertyAwaitable’ does not contain a definition for ‘GetAwaiter’ and no extension method ‘GetAwaiter’ accepting a first argument of type ‘PropertyAwaitable’ could be found (are you missing a using directive or an assembly reference?)

Test.cs(21,25): error CS1986: The ‘await’ operator requires that its operand ‘PropertyAwaitable’ have a suitable public GetAwaiter method

This wasn’t trying truly weird things like awaiting a class name. Oh well :(

Conclusion

Either I’ve misread the spec, or the CTP doesn’t fully comply to it. This should come as no surprise. It’s not a final release or even a beta. However, it’s fun to investigate the limits of what should be valid. The next question is whether the compiler should be changed, or the spec… I can’t immediately think of any really useful patterns involving returning delegates from properties, for example… so is it really worth changing the compiler to allow it?

 

Update (7th November 2010)

On Thursday I spoke to Mads Torgersen and Lucian Wischik about this. Some changes being considered:

  • The C# spec being tightened up to explicitly say that GetAwaiter/BeginAwait/EndAwait have to be methods, at least when statically typed. In other words, the delegate/property version wouldn’t be expected to work.
  • The BeginAwait pattern may be tightened up to require a return type of exactly Boolean or dynamic (rather than the call being "a boolean-expression" which is very slightly more lax)
  • The dynamic version working – this is more complicated in terms of implementation than one might expect

Just to emphasize, these are changes under consideration rather than promises. They seem entirely reasonable to me. (Dynamic binding sounds potentially useful; property/field resolution definitely less so. Making the spec match the implementation is important to me though :)

C# 5 async: investigating control flow

Yes, this has been a busy few days for blog posts. One of the comments on my previous blog post suggested there may be some confusion over how the control flow works with async. It’s always very possible that I’m the one who’s confused, so I thought I’d investigate.

This time I’m not even pretending to come up with a realistic example. As with my previous code, I’m avoiding creating a .NET Task myself, and sticking with my own custom "awaiter" classes. Again, the aim is to give more insight into what the C# compiler is doing for us. I figure other blogs are likely to concentrate on useful patterns and samples – I’m generally better at explaining what’s going on under the hood from a language point of view. That’s easier to achieve when almost everything is laid out in the open, instead of using the built-in Task-related classes.

That’s not to say that Task doesn’t make an appearance at all, however – because the compiler generates one for us. Note in the code below how the return type of DemonstrateControlFlow is Task<int>, whereas the return value is only an int. The compiler uses Task<T> to wrap up the asynchronous operation. As I mentioned before, that’s the one thing the compiler does which actually requires knowledge of the framework.

The aim of the code is purely to demonstrate how control flows. I have a single async method which executes 4 other "possibly asynchronous" operations:

  • The first operation completes synchronously
  • The second operation completes asynchronously, starting a new thread
  • The third operation completes synchronously
  • The fourth operation completes asynchronously
  • The result is then "returned"

At various points in the code I log where we’ve got to and on what thread. In order to execute a "possibly asynchronous" operation, I’m simply calling a method and passing in a string. If the string is null, the operation completes syncrhonously. If the string is non-null, it’s used as the name of a new thread. The BeginAwait method creates the new thread, and returns true to indicate that the operation is completing asynchronously. The new thread waits half a second (to make things clearer) and then executes the continuation passed to BeginAwait. If you remember, that continuation represents "the rest of the method" – the work to do after the asynchronous operation has completed.

Without further ado, here’s the complete code. As is almost always the case with my samples, it’s a console app:

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

public class ControlFlow
{
    static void Main()
    {
        Thread.CurrentThread.Name = "Main";
        
        Task<int> task = DemonstrateControlFlow();
        LogThread("Main thread after calling DemonstrateControlFlow");
        
        // Waits for task to complete, then retrieves the result
        int result = task.Result;        
        LogThread("Final result: " + result);
    }
    
    static void LogThread(string message)
    {
        Console.WriteLine("Thread: {0}  Message: {1}",
                          Thread.CurrentThread.Name, message);
    }
    
    static async Task<int> DemonstrateControlFlow()
    {
        LogThread("Start of method");
        
        // Returns synchronously (still on main thread)
        int x = await MaybeReturnAsync(null);        
        LogThread("After first await (synchronous)");
        
        // Returns asynchronously (return task to caller, new
        // thread is started by BeginAwait, and continuation
        // runs on that new thread).
        x += await MaybeReturnAsync("T1");        
        LogThread("After second await (asynchronous)");
        
        // Returns synchronously – so we’re still running on
        // the first extra thread
        x += await MaybeReturnAsync(null);
        LogThread("After third await (synchronous)");
            
        // Returns asynchronously – starts up another new
        // thread, leaving the first extra thread to terminate,
        // and executing the continuation on the second extra thread.
        x += await MaybeReturnAsync("T2");
        LogThread("After fourth await (asynchronous)");
        
        // Sets the result of the task which was returned ages ago;
        // when this occurs, the main thread
        return 5;
    }
    
    /// <summary>
    /// Returns a ResultFetcher which can have GetAwaiter called on it.
    /// If threadName is null, the awaiter will complete synchronously
    /// with a return value of 1. If threadName is not null, the
    /// awaiter will complete asynchronously, starting a new thread
    /// with the given thread name for the continuation. When EndAwait
    /// is called on such an asynchronous waiter, the result will be 2.
    /// </summary>
    static ResultFetcher<int> MaybeReturnAsync(string threadName)
    {
        return new ResultFetcher<int>(threadName, threadName == null ? 1 : 2);
    }
}

/// <summary>
/// Class returned by MaybeReturnAsync; only exists so that the compiler
/// can include a call to GetAwaiter, which returns an Awaiter[T].
/// </summary>
class ResultFetcher<T>
{
    private readonly string threadName;
    private readonly T result;
    
    internal ResultFetcher(string threadName, T result)
    {
        this.threadName = threadName;
        this.result = result;
    }
    
    internal Awaiter<T> GetAwaiter()
    {
        return new Awaiter<T>(threadName, result);
    }
}

/// <summary>
/// Awaiter which actually starts a new thread (or not, depending on its
/// constructor arguments) and supplies the result in EndAwait.
/// </summary>
class Awaiter<T>
{
    private readonly string threadName;
    private readonly T result;
    
    internal Awaiter(string threadName, T result)
    {
        this.threadName = threadName;
        this.result = result;
    }
    
    internal bool BeginAwait(Action continuation)
    {
        // If we haven’t been given the name of a new thread, just complete
        // synchronously.
        if (threadName == null)
        {
            return false;
        }

        // Start a new thread which waits for half a second before executing
        // the supplied continuation.
        Thread thread = new Thread(() =>
        {
            Thread.Sleep(500);
            continuation();
        });
        thread.Name = threadName;
        thread.Start();
        return true;
    }

    /// <summary>
    /// This is called by the async method to retrieve the result of the operation,
    /// whether or not it actually completed synchronously.
    /// </summary>
    internal T EndAwait()
    {
        return result;
    }
}

And here’s the result:

Thread: Main  Message: Start of method
Thread: Main  Message: After first await (synchronous)
Thread: Main  Message: Main thread after calling DemonstrateControlFlow
Thread: T1  Message: After second await (asynchronous)
Thread: T1  Message: After third await (synchronous)
Thread: T2  Message: After fourth await (asynchronous)
Thread: Main  Message: Final result: 5

A few things to note:

  • I’ve used two separate classes for the asynchronous operation: the one returned by the MaybeReturnAsync method (ResultFetcher<T>),  and the Awaiter<T> class returned by ResultFetcher<T>.GetAwaiter(). In the previous blog post I used the same class for both aspects, and GetAwaiter() returned this. It’s not entirely clear to me under what situations a separate awaiter class is desirable. It feels like it should mirror the IEnumerable<T>/IEnumerator<T> reasoning for iterators, but I haven’t thought through the details of that just yet.
  • If a "possibly asynchronous" operation actually completes synchronously, it’s almost as if we didn’t use "await" at all. Note how the "After first await" is logged on the Main thread, and "After third await" is executed on T1 (the same thread as the "After second await" message). I believe there could be some interesting differences if BeginAwait throws an exception, but I’ll investigate that in another post.
  • When the first "properly asynchronous" operation executes, that’s when control is returned to the main thread. It doesn’t have the result yet of course, but it has a task which it can use to find out the result when it’s ready – as well as checking the status and so on.
  • The compiler hasn’t created any threads for us – the only extra threads were created explicitly when we began an asynchronous operation. One possible difference between this code and a real implementation is that MaybeReturnAsync doesn’t actually start the operation itself at all. It creates something which is able to start the operation, but waits until the BeginAwait call before it starts the thread. This made our example easier to write, because it meant we could wait until we knew what the continuation would be before we started the thread.
  • The return statement in our async method basically sets the result in the task. At that point in this particular example, our main thread is blocking, waiting for the result – so it becomes unblocked as soon as the task has completed.

If you’ve been following along with Eric, Anders and Mads, I suspect that none of this is a surprise to you, other than possibly the details of the methods called by the compiler (which are described clearly in the specification). I believe it’s worth working through a simple-but-useless example like this just to convince you that you know what’s going on. If the above isn’t clear – either in terms of what’s going on or why, I’d be happy to draw out a diagram with what’s happening on each thread. As I’m rubbish at drawing, I’ll only do that when someone asks for it.

Next topic: well, what would you like it to be? I know I’ll want to investigate exception handling a bit soon, but if there’s anything else you think I should tackle first, let me know in the comments.

C# 5 async and choosing terminology: why I’m against “yield”

Eric Lippert’s latest (at the time of this writing) blog post asks for suggestions for alternatives to the new "await" keyword, which has inappropriate connotations that confuse people. In particular, it sounds like the thread is going to sit there waiting for the result, when the whole point is that it doesn’t.

There have been many suggestions in the comments, and lots of them involve "yield". I was initially in favour of this too, but on further reflection I don’t think it’s appropriate, for the same reason: it has a connotation which may not be true. It sounds like it’s always going to yield control, when sometimes it doesn’t. To demonstrate this, I’ve come up with a tiny example. It’s a stock market class which allows you to compute the total value of your holdings asynchronously. The class would make web service calls to fetch real prices, but then cache values for some period. The caching bit is the important part here – and in fact it’s the only part I’ve actually implemented.

The point is that when the asynchronous "total value" computation can fetch a price from the cache, it doesn’t need to wait for anything, so it doesn’t need to yield control. This is the purpose of the return value of BeginAwait: if it returns false, the task has been completed and EndAwait can be called immediately. In this case the continuation is ignored – when BeginAwait returns, the ComputeTotalValue method keeps going rather than returning a Task to the caller.

Here’s the complete code:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

class Test
{
    static void Main()
    {
        StockMarket market = new StockMarket();
        market.AddCached("GOOG", 613.70m);
        market.AddCached("MSFT", 26.67m);
        market.AddCached("AAPL", 300.98m);
        
        Task<decimal> total = market.ComputeTotalValueAsync(
            Tuple.Create("AAPL", 10),
            Tuple.Create("GOOG", 20),
            Tuple.Create("MSFT", 25)
        );
        Console.WriteLine("Completed already? {0}", total.IsCompleted);
        Console.WriteLine("Total value: {0}", total.Result);
    }
}

class StockMarket
{
    private readonly Dictionary<string, decimal> cache =
        new Dictionary<string, decimal>();
    
    internal void AddCached(string ticker, decimal price)
    {
        cache[ticker] = price;
    }
    
    public async Task<decimal> ComputeTotalValueAsync(params Tuple<string, int>[] holdings)
    {
        // In real code we may well want to parallelize this, of course
        decimal total = 0m;
        foreach (var pair in holdings)
        {
            total += await new StockFetcher(this, pair.Item1) * pair.Item2;
        }
        Console.WriteLine("Diagnostics: completed ComputeTotalValue");
        return total;
    }
    
    private class StockFetcher
    {
        private readonly StockMarket market;
        private readonly string ticker;
        private decimal value;
        
        internal StockFetcher(StockMarket market, string ticker)
        {
            this.market = market;
            this.ticker = ticker;
        }
        
        internal StockFetcher GetAwaiter()
        {
            return this;
        }
        
        internal bool BeginAwait(Action continuation)
        {
            // If it’s in the cache, we can complete synchronously
            if (market.cache.TryGetValue(ticker, out value))
            {            
                return false;
            }
            // Otherwise, we need to make an async web request and do
            // cunning things. Not implemented :)
            throw new NotImplementedException("Oops.");
        }
        
        internal decimal EndAwait()
        {
            // Usually more appropriate checking here, of course
            return value;
        }
    }
}

(Note that we’d probably have a public method to fetch a single stock value asynchronously too, and that would probably return a task – in this case I wanted to keep everything as simple as possible, not relying on any other implementation of asynchrony. This also shows how the compiler uses GetAwait/BeginAwait/EndAwait… and that they don’t even need to be public methods.)

The result shows that everything was actually computed synchronously – the returned task is complete by the time the method returns. You may be wondering why we’ve bothered using async at all here – and the key is the bit that throws the NotImplementedException. While everything returns synchronously in this case, we’ve allowed for the possibility of asynchronous fetching, and the only bit of code which would need to change is BeginAwait.

So what does this have to do with the choice of keywords? It shows that "yield" really isn’t appropriate here. When the action completes very quickly and synchronously, it isn’t yielding at all.

What’s the alternative?

There are two aspects of the behaviour of the current "await" contextual keyword:

  • We might yield control, returning a task to the caller.
  • We will continue processing at some point after the asynchronous subtask has completed – whether it’s completed immediately or whether our continuation is called back.

It’s hard to capture both of those aspects in one or two words, but I think it make sense to at least capture the aspect which is always valid. So I propose something like "continue after":

foreach (var pair in holdings) 

    total += continue after new StockFetcher(this, pair.Item1) * pair.Item2; 
}

I’m not particularly wedded to the "after" bit – it could be "when" or "with" for example.

I don’t think this is perfect – I’m really just trying to move the debate forward a bit. I think the community doesn’t really have enough of a "feeling" for the new feature yet to come up with a definitive answer at the moment (and I include myself there). I think focusing on which aspects we want to emphasize – with a clear understanding of how the feature actually behaves – it a good start though.

Initial thoughts on C# 5’s async support

As many of you will have seen yesterday, the major new feature of C# 5 was announced yesterday: support for asynchronous operations with new contextual keywords of "async" and "await". I haven’t had a lot of time to play with them yet, but I have a few initial thoughts. Note that these won’t make any sense to you unless you’ve also watched the talk Anders gave, or read Eric’s blog post, or something similar. Links are at the bottom of this post rather than peppered throughout.

Asynchronous != parallel

Do you remember when LINQ was first announced, and there was a huge fear that it was effectively putting SQL into C#, when in fact the truth was more general? Well, it’s the same here. The language feature allows a method to execute asynchronously, but it won’t create new threads and the like automatically.

I suspect there’s going to be a lot of confusion about which parts of the asynchronous model are provided by the language and which by the framework. Obviously I’ll hope to clarify things where I can, but it’s important to understand that the language isn’t going to automatically start extra threads or anything like that.

In the Channel9 PDC interview, Anders stressed this point pretty hard – which suggests he thinks it’s going to cause confusion too. I became a lot more comfortable with what’s going on after reading the draft spec – which is part of the CTP.

Language and framework interaction

It looks like the language changes have been designed to be pattern-based, a little like LINQ and foreach. The async modifier is present more for the sake of developers than the compiler, and the await contextual keyword simply requires a GetAwaiter() method to be available (which can be an extension method); that method has to return something for which BeginAwait(Action) and EndAwait() are valid – and again, these can be extension methods.

One of the tests I performed yesterday was to try to use this myself, with a custom "awaiter factory" – it worked fine, and it’s definitely an interesting way of exploring what’s going on. Expect a blog post along those lines some time next week.

So far, so framework-neutral… the only slight fly in the ointment is the reliance on Task and Task<T>. Just as an iterator block with yield return 10; would usually be declared to return IEnumerable<int>, so an async method ending in return 10; would have a return type of Task<int>. I don’t think that’s actually too bad – but I’ll have to dig into exactly what the language relies on to be completely comfortable with. Are there any aspects of tasks which are usually configured by their factories, for example? If so, what does the compiler do?

My gut feeling is that the language is still keeping the framework at an appropriate distance as far as it can, but that it’s got to have something like Task<T> as a way of representing an asynchronous operation.

But is it any use?

Again, I’m really going on gut feelings so far. I think it’s going to be very useful – and I wish I had something similar in Java when writing internal services at work. I like the fact that it’s relatively simple – it feels much simpler than dynamic typing, for example – so I think I’ll be able to get my head round it.

It’s important to note that it’s not a free lunch, and doesn’t try to be. It removes much of the error-prone mechanical drudgery of writing asynchronous code, but it doesn’t attempt to magically parallelize everything you do. You still need to think about what makes sense to do asynchronously, and how to introduce parallelism where appropriate. That’s a really good thing, in my view: it’s about managing complexity rather than hiding it.

Conclusion

I think C# 5 is going to be a lot of fun… but I also think you’re going to need to understand the Task Parallel Library to really make the most of it. Keep the two separate in your head, and understand how they complement each other. If ever there was a good time to learn TPL thoroughly, it’s now. Learning the C# 5 features themselves won’t take long. Mastering the combination of the two in a practical way could be a much bigger task.

Links

Obviously there are lots of resources flooding out of Microsoft (and other bloggers) at the moment. Here are a few to start with:

  • The Visual Studio async home – probably the best site to bookmark, as I’m sure it’ll get updated over time. Download the CTP from here, as well as watching various videos.
  • PDC 2010 player – as this was announced at PDC, there are lots of talks there, including the session where Anders introduces the feature.
  • Eric Lippert’s first blog post on async – with more to come, of course. Follow the Async or C# 5.0 tags.
  • A blog post by Michael Crump with a CTP walkthrough