Tag Archives: asynchronous programming

Async/Await Crash Course

I’ve known about Microsoft’s asynchronous programming since hearing the announcement at PDC 2010. I’ve been aware of it, and I’ve dabbled here and there, but I haven’t really gotten into using it as part of my standard toolkit for a variety of reasons. First, it was that the product I was focused on could only use .Net Framework 3.5. Then I was on another product that used .Net 4.0, but we didn’t have much need for performance tuning.

But now I’m in a world where I have access to it AND a need for it–hooray! And so, with that, I present to you my crash course on asynchronous programming in c# using the async and await keywords.

Let me set up a scenario for my examples. Imagine a function that matches records between two systems. Data must be retrieved from each of the two systems before the matching can be performed.

Here’s what a fully-synchronous version of the problem might look like. Note that data is being loaded one-type and one-source at a time, followed by matching for that type.

public void DoMatching()
{
    var fooFromA = GetFooFromA();
    var fooFromB = GetFooFromB();
    Match(fooFromA, fooFromB);
    Console.WriteLine("{0} foo matched!", fooFromB.Count(x => x.IsMatch));
    
    var barFromA = GetBarFromA();
    var barFromB = GetBarFromB();
    Match(barFromA, barFromB);
    Console.WriteLine("{0} bar matched!", barFromB.Count(x => x.IsMatch));
}

public IEnumerable<Foo> GetFooFromA()
{
    var data = new Foo[] { new Foo(1), new Foo(2), new Foo(3) };
    return data;
}

public IEnumerable<Foo> GetFooFromB()
{
    var data = new Foo[] { new Foo(2), new Foo(3), new Foo(4) };
    return data;
}

public IEnumerable<Bar> GetBarFromA()
{
    var data = new Bar[] { new Bar("one"), new Bar("two"), new Bar("three") };
    return data;
}

public IEnumerable<Bar> GetBarFromB()
{
    var data = new Bar[] { new Bar("two"), new Bar("three"), new Bar("four") };
    return data;
}

public void Match(IEnumerable<Foo> fooFromA, IEnumerable<Foo> fooFromB)
{
    foreach (var foo in fooFromB)
    {
        if (fooFromA.Any(x => x.Id == foo.Id))
        {
            foo.IsMatch = true;
        }
    }
}

public void Match(IEnumerable<Bar> barFromA, IEnumerable<Bar> barFromB)
{
    foreach (var bar in barFromB)
    {
        if (barFromA.Any(x => x.Id == bar.Id))
        {
            bar.IsMatch = true;
        }
    }
}

public class Foo
{
    public int Id { get; set; }
    public bool IsMatch { get; set; }
    
    public Foo(int id)
    {
        Id = id;
    }
}

public class Bar
{
    public string Id { get; set; }
    public bool IsMatch { get; set; }
    
    public Bar(string id)
    {
        Id = id;
    }
}

The first thing we can do to optimize this code with async/await is to make the data retrieval methods asynchronous. This is done in just three steps:

  1. Change the return type to Task<T>
  2. Add async to the function declaration
  3. Use await to return the value

If the logic in your function blocks the CPU, like mine which just has a hard-coded result, you can make it async-friendly by executing it via Task.Run.

Here’s what the new, async version of my data-getters.

public async Task<IEnumerable<Foo>> GetFooFromA()
{
    return await Task.Run(() => new Foo[] { new Foo(1), new Foo(2), new Foo(3) });
}

public async Task<IEnumerable<Foo>> GetFooFromB()
{
    return await Task.Run(() => new Foo[] { new Foo(2), new Foo(3), new Foo(4) });
}

public async Task<IEnumerable<Bar>> GetBarFromA()
{
    return await Task.Run(() => new Bar[] { new Bar("one"), new Bar("two"), new Bar("three") });
}

public async Task<IEnumerable<Bar>> GetBarFromB()
{
    return await Task.Run(() => new Bar[] { new Bar("two"), new Bar("three"), new Bar("four") });
}

Okay, so that takes care of half the problem, but now we need to make sure the match functions are executed once the data they need is available. One way to do this would be to use the await keyword, like this:

var fooFromA = GetFooFromA();
var fooFromB = GetFooFromB();
Match(await fooFromA, await fooFromB);

But wait! We don’t want to do that because we’ll be preventing the data retrieval and matching of our Bar records while we process our Foo records. Instead, we can use Task.WhenAll to tell our match function to process once the data it needs becomes available.

var fooFromA = GetFooFromA();
var fooFromB = GetFooFromB();
Task.WhenAll(fooFromA, fooFromB).ContinueWith(t => 
{
    Match(fooFromA.Result, fooFromB.Result);
    Console.WriteLine("{0} foo matched!", fooFromB.Result.Count(x => x.IsMatch));
});

Note that in my ContinueWith block, I’m using the Result property of the asynchronous tasks. It’s safe to use the property since WhenAll makes sure they’re finished before getting there. If we wanted to be extra safe, we could check the status of the Task (t) that’s passed into our anonymous function–probably a good idea to verify that nothing went wrong while retrieving the data.

You’ll also notice that I moved the Console.WriteLine into the ContinueWith block. This needs to happen for two reasons. First, the code’s running asynchronously so the matching wouldn’t have occurred by the time the statement was run. Second, the collection might not be accessible if the task hadn’t completed; you could use the await keyword, but even then you could not guarantee that matching had finished.

So now we’re in business. The data retrievals all occur asynchronously, and matching begins as soon as the requisite data is received for each of our respective data types. We haven’t done anything with our DoMatching function, though. If we want to make it awaitable, we just need to keep track of our work tasks and make use of WhenAll again. Notice that we’ve added the async keyword to our method signature and that void has become Task.

public async Task DoMatching()
{
    var fooFromA = GetFooFromA();
    var fooFromB = GetFooFromB();
    var matchFoos = Task.WhenAll(fooFromA, fooFromB).ContinueWith(t => 
    {
        Match(fooFromA.Result, fooFromB.Result);
        Console.WriteLine("{0} foo matched!", fooFromB.Result.Count(x => x.IsMatch));
    });
    
    var barFromA = GetBarFromA();
    var barFromB = GetBarFromB();
    var matchBars = Task.WhenAll(barFromA, barFromB).ContinueWith(t => 
    {
        Match(barFromA.Result, barFromB.Result);
        Console.WriteLine("{0} bar matched!", barFromB.Result.Count(x => x.IsMatch));
    });
    
    await Task.WhenAll(matchFoos, matchBars);
}

Complete example:

void Main()
{
    DoMatching().Wait();
}

public async Task DoMatching()
{
    var fooFromA = GetFooFromA();
    var fooFromB = GetFooFromB();
    var matchFoos = Task.WhenAll(fooFromA, fooFromB).ContinueWith(t => 
    {
        Match(fooFromA.Result, fooFromB.Result);
        Console.WriteLine("{0} foo matched!", fooFromB.Result.Count(x => x.IsMatch));
    });
    
    var barFromA = GetBarFromA();
    var barFromB = GetBarFromB();
    var matchBars = Task.WhenAll(barFromA, barFromB).ContinueWith(t => 
    {
        Match(barFromA.Result, barFromB.Result);
        Console.WriteLine("{0} bar matched!", barFromB.Result.Count(x => x.IsMatch));
    });
    
    await Task.WhenAll(matchFoos, matchBars);
}

public async Task<IEnumerable<Foo>> GetFooFromA()
{
    return await Task.Run(() => new Foo[] { new Foo(1), new Foo(2), new Foo(3) });
}

public async Task<IEnumerable<Foo>> GetFooFromB()
{
    return await Task.Run(() => new Foo[] { new Foo(2), new Foo(3), new Foo(4) });
}

public async Task<IEnumerable<Bar>> GetBarFromA()
{
    return await Task.Run(() => new Bar[] { new Bar("one"), new Bar("two"), new Bar("three") });
}

public async Task<IEnumerable<Bar>> GetBarFromB()
{
    return await Task.Run(() => new Bar[] { new Bar("two"), new Bar("three"), new Bar("four") });
}

public void Match(IEnumerable<Foo> fooFromA, IEnumerable<Foo> fooFromB)
{
    foreach (var foo in fooFromB)
    {
        if (fooFromA.Any(x => x.Id == foo.Id))
        {
            foo.IsMatch = true;
        }
    }
}

public void Match(IEnumerable<Bar> barFromA, IEnumerable<Bar> barFromB)
{
    foreach (var bar in barFromB)
    {
        if (barFromA.Any(x => x.Id == bar.Id))
        {
            bar.IsMatch = true;
        }
    }
}

public class Foo
{
    public int Id { get; set; }
    public bool IsMatch { get; set; }
    
    public Foo(int id)
    {
        Id = id;
    }
}

public class Bar
{
    public string Id { get; set; }
    public bool IsMatch { get; set; }
    
    public Bar(string id)
    {
        Id = id;
    }
}
Advertisements

Events with Return Values

I was working with a team on an interface project that allowed for the transferring of records between N different systems. Once the record was transferred, updates can flow in both directions. I suggested that we use events to begin transactions from source systems, and the event arguments would contain the necessary routing information to help get the data to the correct destination.

Great plan, but we ran into a problem because one of the systems involved uses asynchronous operations for its transactions and another uses synchronous operations. No problem, though. We can get around this with the creative use of callbacks and wait handles.

Let’s look at an example. In the code below, the application calls a method that raises an event. The method needs to return a response, and the event handler produces a response, but there is no way to return the response from the event handler to the method.

class Program
{
    static event EventHandler<SampleEventArgs> Sample;

    static void Main(string[] args)
    {
        Sample += SampleEventHandler;
        var response = RaiseAnEvent();
        Console.WriteLine("Response: {0}", response);
        Console.ReadLine();
    }

    static string RaiseAnEvent()
    {
        if (Sample != null)
        {
            var args = new SampleEventArgs();
            Sample(null, args);
        }
        return null; // need the response!
    }

    static void SampleEventHandler(object sender, SampleEventArgs e)
    {
        string response = "foo";
    }
}

public class SampleEventArgs : EventArgs
{
}

When program runs, the following output is produced:

Response: 

The first problem we need to deal with is that the event handler needs a way to provide its response to the calling code. This could be accomplished by adding a response property to the event argument OR by adding a callback to the event argument. I prefer the latter because the former will require me to know when it is safe to retrieve the value from the event argument whereas the callback is more like a “push.” So, let’s add a callback!

public class SampleEventArgs : EventArgs
{
    public Action<string> SampleCompleted { get; set; }
}

Now that we have the ability to specify a callback to capture the response, guess what the next step is. That’s, right: create the callback method! This is also our opportunity to block execution while we wait for a response. I’ll use a ManualResetEvent to block execution, and I’ll set it in the callback. Perfect, and lambdas make the whole thing a breeze!

static string RaiseAnEvent()
{
    string response = null;
    if (Sample != null)
    {
        var args = new SampleEventArgs();
        var manualResetEvent = new ManualResetEvent(false);
        args.SampleCompleted = r =>
            {
                response = r;
                manualResetEvent.Set();
            };
        Sample(null, args);

        if (!manualResetEvent.WaitOne(1000))
        {
            // timeout waiting for response
        }
    }
    return response;
}

Now that we’ve got our callback created and defined, we just need the event handler to invoke it.

static void SampleEventHandler(object sender, SampleEventArgs e)
{
    string response = "foo";
    if (e.SampleCompleted != null)
    {
        e.SampleCompleted(response);
    }
}

And with that, we’re done! We run the application, and we get the expected output.

Response: foo

Complete sample:

namespace EventsWithReturnValues
{
    using System;
    using System.Threading;

    class Program
    {
        static event EventHandler<SampleEventArgs> Sample;

        static void Main(string[] args)
        {
            Sample += SampleEventHandler;
            var response = RaiseAnEvent();
            Console.WriteLine("Response: {0}", response);
            Console.ReadLine();
        }

        static string RaiseAnEvent()
        {
            string response = null;
            if (Sample != null)
            {
                var args = new SampleEventArgs();
                var manualResetEvent = new ManualResetEvent(false);
                args.SampleCompleted = r =>
                    {
                        response = r;
                        manualResetEvent.Set();
                    };
                Sample(null, args);

                if (!manualResetEvent.WaitOne(1000))
                {
                    // timeout waiting for response
                }
            }
            return response;
        }

        static void SampleEventHandler(object sender, SampleEventArgs e)
        {
            string response = "foo";
            if (e.SampleCompleted != null)
            {
                e.SampleCompleted(response);
            }
        }
    }

    public class SampleEventArgs : EventArgs
    {
        public Action<string> SampleCompleted { get; set; }
    }
}