Archive

Posts Tagged ‘C# 5.0’

A Boring Discovery!

August 28, 2012 3 comments

I was writing a simple example program to explain C#5’s async/await keywords. To keep it really simple and “old school”, I decided to make it a console app, and to read lines from the console until the user typed quit. First, the synchronous version:

public static List<string> Foo()
{
    var lines = new List<string>();

    string line;
    while ((line = Console.In.ReadLine()) != "quit")
        lines.Add(line);

    return lines;
}

And then the async version:

public static async Task<List<string>> Foo()
{
    var lines = new List<string>();

    string line;
    while ((line = await Console.In.ReadLineAsync()) != "quit")
        lines.Add(line);

    return lines;
}

Really straightforward, right? I just add the async keyword, wrap the return type inside Task<T> and then I can use await Console.In.ReadLineAsync() instead of Console.In.ReadLine().

So I tried this, and gosh-dang-diddly, it didn’t behave at all as expected. In fact, both versions behaved the same. Could it be something exciting to do with how the SynchronizationContext is set up in console apps? Sorry, no. Try to think of something much duller than that.

The answer is… wait for it… ReadLineAsync() isn’t asynchronous at all. It doesn’t return its Task<string> until the whole line has been read.

Why is that? TextReader.ReadLineAsync appears to be properly asynchronous, and Console.In returns a TextReader as you’d expect… but not quite. It first passes it to TextReader.Synchronized, and guess how the resulting wrapper class implements ReadLineAsync? Thanks to .NET Reflector, we don’t have to guess:

public override Task<string> ReadLineAsync()
{
    return Task.FromResult<string>(this.ReadLine());
}

Yep, it calls ordinary ReadLine, totally synchronously, and then makes an already-finished Task<string>. In real life this is probably harmless because it’s such an edge case, but you can imagine the tedious diversion it caused in the middle of the explanation I was giving.

To get around it, I used this alternative helper, to move the ReadLine to the thread pool:

public static Task<string> ReadConsoleAsync()
{
    return Task.Run(() => Console.ReadLine());
}

Moral: I have no idea. How about “Sometimes, things don’t exactly work.” Is that a moral?

Categories: Uncategorized Tags: , ,

Async/await iterator – updated for Visual Studio 11 Preview

January 29, 2012 2 comments

A long overdue install of the Visual Studio 11 Preview, and the changes to the asynchronous language features since 2010 (my, how time flies) are enough to break the code I blogged over a year ago.

The first problem is a few of the methods of an “awaiter” (what in C++ we’d call the awaiter concept) have been renamed, and there’s now a property called IsCompleted, and that’s fine and dandy.

But when I tried exercising the code I hit a more thorny problem, which is that my test program would terminate somewhat randomly when an exception was rethrown from a background thread. For a program that I thought was single threaded, that’s pretty bad!

I don’t have my install of the original CTP, so I’m not sure about this, but I think a fairly major change was made since then: there’s now a difference between an async method that returns void and an async method that returns Task (as opposed to Task<T>).

Contrary to what might be assumed, the relationship between Task and Task<T> is not the same as that between IEnumerable and IEnumerable<T>. That is, Task is not some old pre-generics version of the same idea. Instead, it was specially created to represent a task that doesn’t return any value at all; that is, something like void, but asynchronous.

I believe (though I’m not certain) that in the original CTP, a void async method would actually return a Task, so as to ensure that its lifetime could be managed externally even though it wouldn’t produce a value. But in the latest version that is not the case: the Task associated with an void async method is just not available, and the compiler generated version of the method really does return void. Which means in turn that you can’t use await on such methods.

You can still explicitly declare your async method to return Task, so nothing has been lost. And this certainly makes everything more clear and consistent to callers: methods really do return what they are declared to return, as usual. But it also changes the behaviour of exceptions.

In all case, if an exception tries to escape out of your async method, there is a catch-all handler in the compiler-generated state machine which will catch it, so it can be rethrown in an appropriate context. But the choice of context depends totally on whether the method returns void or Task. The policy is determined by AsyncVoidMethodBuilder or AsyncTaskMethodBuilder respectively. With the help of Resharper, we can see that the latter gives the caught exception to the Task, via task.TrySetException. So then the decision to rethrow (or not) is entirely up to whoever has a hold of the Task. They can check the Exception property whenever.

But in the void case, it’s totally different. The Task never gets passed the exception. What would be the point? We can’t get at the Task. The exception is unobservable; to avoid that loss of information, an arrangement is made to rethrow the exception at the next available opportunity, by creating a delegate that will rethrow it and then posting that delegate to the “context”.

The “context” is a somewhat vague concept; the architecture uses three different representations, depending on the scenario. But in the case of a simple console-based test program, the exception-rethrowing delegate is simply passed to the thread pool, and so it brings down the whole process at a random time (though reasonably soon). In a GUI program the exception would be thrown on the main GUI thread. You can supply your own context by setting a per-thread instance of SynchronizationContext, in which you can override the Post method. It doesn’t let you get at the exception, but it does give you a delegate that, if you executed it, would throw the exception, which you can then catch!

The upshot? An exception that leaves an async void is definitely a sign of a bug somewhere. Although of course this does not automatically mean you should add your own catch-all! Sometimes crashing the process is the least-worst option. There is no single correct way to deal with bugs – it’s a question of economics and so is not an exact science.

So in short, async void is a niche thing. In most situations you almost certainly want async Task with no type argument. And my example of implementing the equivalent of yield return definitely needs updating.

Firstly I stash the Task in a field. Second, after executing the continuation I check the Task.Exception property to see if anything bad happened that needs rethrowing:

if (_task.Exception != null)
{
    // Unpeel the AggregateException wrapping
    Exception inner = _task.Exception;
    while (inner is AggregateException)
        inner = inner.InnerException;

    throw inner;
}

Aside from that it works much the same way as before, though I’ve added a lot of comments and organised it a little differently to hopefully make the behaviour clearer. I’ve also had to add an implementation of the new awaiter property:

public bool IsCompleted
{
    get { return false; }
}

Well, that was easy. Returning true would be a very bad idea in this example, as we can discover with more Resharper digging. The compiler-generated state machine examines that property, and if it is true then it doesn’t bother to yield control back to the thread. So we don’t get the interleaved execution behaviour that we’re relying on.

Here’s the whole thing:

public delegate Task IteratorMethod(YieldEnumerator e);

public class YieldEnumerator : IEnumerator
{
    // Will be executed to get the next value
    private Action _continuation;

    // Will become the value of Current
    private TItem _nextValue;
    private bool _hasNextValue;

    // To be thrown inside the async method, as if by the await keyword
    private Exception _exception;

    // The task associated with our running async method
    private Task _task;

    public YieldEnumerator(IteratorMethod iteratorMethod)
    {
        _task = iteratorMethod(this);
    }

    private void Execute()
    {
        // If we already have a buffered value that hasn't been
        // retrieved, we shouldn't do anything yet. If we don't
        // and there's no continuation to run, we've finished.
        // And if _task is null, we've been disposed.
        if (_hasNextValue || _continuation == null || _task == null)
            return;

        // Be ultra-careful not to run same _continuation twice
        var t = _continuation;
        _continuation = null;
        t(); // may or may not have stored a new _continuation

        // And may also have hit a snag!
        if (_task.Exception != null)
        {
            // Unpeel the AggregateException wrapping
            Exception inner = _task.Exception;
            while (inner is AggregateException)
                inner = inner.InnerException;

            throw inner;
        }
    }

    public YieldEnumerator GetAwaiter()
    {
        return this;
    }

    // Performance optimisation added since original CTP. If we
    // returned true, the compiler-generated code would bypass the
    // OnCompleted/GetResult dance altogether, and the flow of the
    // async method would never be interrupted in the way that we
    // require.
    public bool IsCompleted
    {
        get { return false; }
    }

    // Was called BeginAwait in the original CTP
    public void OnCompleted(Action continuation)
    {
        Debug.Assert(_continuation == null);
        _continuation = continuation;
    }

    // Was called EndAwait
    public void GetResult()
    {
        // This is called by compiler-generated code caused by the
        // await keyword, so it's a chance to throw an exception to
        // be caught by the code in the async method
        if (_exception != null)
        {
            var t = _exception;
            _exception = null;
            throw t;
        }
    }

    // Our equivalent of yield return
    public YieldEnumerator YieldReturn(TItem value)
    {
        if (_hasNextValue)
        {
            // Shouldn't happen because MoveNext ought to have
            // been called and we should be inside the async
            // code at this point
            throw new InvalidOperationException();
        }

        _nextValue = value;
        _hasNextValue = true;
        return this;
    }

    public TItem Current { get; private set; }

    object System.Collections.IEnumerator.Current
    {
        get { return Current; }
    }

    public bool MoveNext()
    {
        Execute();

        if (_hasNextValue)
        {
            Current = _nextValue;
            _hasNextValue = false;
            return true;
        }

        return false;
    }

    private sealed class AbandonEnumeratorException : Exception {}

    public void Dispose()
    {
        // If async method is not yet complete, throw an exception
        // inside it to make it grind to a halt
        if (_continuation != null)
        {
            _exception = new AbandonEnumeratorException();
            try { Execute(); } catch (AbandonEnumeratorException) { }
        }

        _task.Dispose();
        _task = null;
    }

    public void Reset()
    {
        throw new NotImplementedException("Reset");
    }
}

// The usual obvious IEnumerable to go with our IEnumerator
public class YieldEnumerable : IEnumerable
{
    private readonly IteratorMethod _iteratorMethod;

    public YieldEnumerable(IteratorMethod iteratorMethod)
    {
        _iteratorMethod = iteratorMethod;
    }

    public IEnumerator GetEnumerator()
    {
        return new YieldEnumerator(_iteratorMethod);
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

class Program
{
    public static async Task MyIteratorMethod1(YieldEnumerator e)
    {
        Console.WriteLine("A");
        await e.YieldReturn(1);
        Console.WriteLine("B");
        await e.YieldReturn(2);
        Console.WriteLine("C");
        await e.YieldReturn(3);
        Console.WriteLine("D");
    }

    public static async Task MyIteratorMethod2(YieldEnumerator e)
    {
        try
        {
            Console.WriteLine("A");
            await e.YieldReturn(1);
            Console.WriteLine("B");
            await e.YieldReturn(2);
            Console.WriteLine("C");
            await e.YieldReturn(3);
            Console.WriteLine("D");
        }
        finally
        {
            Console.WriteLine("Running finally");
        }
    }

    public static async Task MyIteratorMethodInfinite(YieldEnumerator e)
    {
        for (var n = 0; ; n++)
            await e.YieldReturn(n);
    }

    public static async Task MyIteratorBroken1(YieldEnumerator e)
    {
        // always happens, but compiler doesn't know that
        if (DateTime.Now.Year < 10000)
            throw new IOException("Bad");

        await e.YieldReturn(1);
    }

    public static async Task MyIteratorBroken2(YieldEnumerator e)
    {
        await e.YieldReturn(1);

        if (DateTime.Now.Year < 10000)
            throw new IOException("Bad");
    }

    public static async Task MyIteratorBroken3(YieldEnumerator e)
    {
        await e.YieldReturn(1);

        if (DateTime.Now.Year < 10000)
            throw new IOException("Bad");

        await e.YieldReturn(2);
    }

    static void Main(string[] args)
    {
        foreach (var i in new YieldEnumerable(MyIteratorMethod1))
            Console.WriteLine("Yielded: " + i);

        foreach (var i in new YieldEnumerable(MyIteratorMethod2))
        {
            Console.WriteLine("Yielded: " + i);
            break; // finally should still run
        }

        foreach (var i in new YieldEnumerable(MyIteratorMethodInfinite))
        {
            if (i % 1000000 == 0) // every million times...
                Console.WriteLine("Yielded: " + i);

            if (i > 10000000)
                break;
        }

        try
        {
            foreach (var i in new YieldEnumerable(MyIteratorBroken1))
                Console.WriteLine("Yielded: " + i);
        }
        catch (IOException)
        {
            Console.WriteLine("Caught expected exception");
        }

        try
        {
            foreach (var i in new YieldEnumerable(MyIteratorBroken2))
                Console.WriteLine("Yielded: " + i);
        }
        catch (IOException)
        {
            Console.WriteLine("Caught expected exception");
        }

        try
        {
            foreach (var i in new YieldEnumerable(MyIteratorBroken3))
                Console.WriteLine("Yielded: " + i);
        }
        catch (IOException)
        {
            Console.WriteLine("Caught expected exception");
        }
    }
}
Categories: Uncategorized Tags: , ,

Unification of async, await and yield return

December 14, 2010 14 comments

The new await facility in the C# 5 CTP is mightly reminiscent of the iterator methods (yield return) added in C# 2. So much so that it is irresistable (to someone like me, anyway) to see if I can reinvent one using the other.

For many years now people have already been implementing something a lot like await using yield return, and I’ve blogged about that before. It’s quite possible to write a simple library such that yield return can play much the same role as await, except for some irritating limitations.

But can we go the other way, and write a library that provides the capability of yield return using only the new await feature?

Short answer: yes.

Long answer: (now read on…)
Read more…

C# 5.0 async/await and GUI events

October 30, 2010 7 comments

A silly example. I’m tickled by the idea of treating a button as a simple task:

async void RefreshButtonAsync()
{
    for (;;)
    {
        await refreshButton.ClickAsync();
            // returns a Task that finishes 
            // next time the button is clicked
        await RefreshAsync();
    }
}

Wait for the button to be clicked, wait for the refresh to finish, repeat forever… that’s your task, little fella!
Read more…

Categories: Uncategorized Tags: , ,

C# 5.0 async/await

October 30, 2010 8 comments

First reaction: hurrah! This is the right language feature at the right time, and a perfect application of the power of compilers. I’ve been using JavaScript for the last few months and constantly wishing for a feature like this, but at the same time thinking how it could be done better in C#.

Second reaction: why would you want to have that await keyword in there?
Read more…

Categories: Uncategorized Tags: , ,