Dan's Green Shoes

Got my green shoes on!

ProModel Coroutines (prior to async/await pattern)

1 Comment

I asked my friend of many years, Terry Foster, to guess post for me on the subject of asynchronous programming.  Terry is the primary author of what we internally call the PAF:  ProModel Application Framework.  One of the features of the PAF is coroutines.  Below you will find Terry’s guest post.

Terry Foster

Terry Foster

It has become increasingly important, and even necessary in many cases, to employ asynchronous programming to improve application responsiveness.  However, the code often required to call asynchronous methods can quickly become convoluted and unmanageable.  The problem lies mainly in the need to provide some kind of handler method to be called when the asynchronous method has completed which prevents the developer from writing code in a straightforward, sequential manner, and instead causes the execution flow to jump around in a way that is typically very difficult to read and maintain.

As a simple illustration, let’s take a class that manages some numerical data and contains two asynchronous methods that we’ll pretend can load and save that data from/to some storage:

public class DataManager
{
public int Data { get; set; }
public void LoadAsync(Action completedCallback)
{
// Load data from storage.
completedCallback();
}

public void SaveAsync(Action completedCallback)
{
// Save data to storage.
completedCallback();
}
}

Now let’s say that we need to provide a feature in our application that can increment this numerical data, meaning we’ll need to load the data, increment it, and then save the change.  You would hope that this would be a fairly straightforward process.  However, the necessary code looks something like this:

public void IncrementData()
{
var dm = new DataManager();
dm.LoadAsync(() => LoadCompleted(dm));
}

private void LoadCompleted(DataManager dm)
{
dm.Data = dm.Data + 1;
dm.SaveAsync(() => SaveCompleted());
}

private void SaveCompleted()
{
Console.WriteLine("Data incremented successfully!");
}

Definitely not as clean and simple as we’d like.  We had to create two methods to handle the completed responses from the asynchronous calls.  Alternatively, we could use anonymous methods to eliminate the two named handler methods:

public void IncrementData()
{
var dm = new DataManager();
dm.LoadAsync(() =>
{
dm.Data = dm.Data + 1;
dm.SaveAsync(() =>
{
Console.WriteLine("Data incremented successfully!");
});
});
}

Not exactly an improvement in readability – and this is a very trivial situation.  It can quickly get much worse.

What would be really nice is if we could kick off an asynchronous call and then suspend the execution of the calling method until the asynchronous call completes, then simply resume the execution of the calling method.  This would cause the program execution to flow in a sequential and intuitive manner, without the need for any handler methods.   There is, in fact, a way to implement this kind of method, and they are called coroutines.

Coroutines can be achieved by employing a mechanism in C# called iterators.  Iterators allow you to create a method that typically loops through a set of data and periodically yields values to the caller.  All it takes to mark a method as an iterator is to make the return type an IEnumerable.  Then the logic of the method can yield values to caller at any point using the keywords yield return , like in this trivial example:

public IEnumerable<double> FindNegatives(List<double> numbers)
{
foreach (double number in numbers)
{
if (number < 0)
{
yield return number;
}
}
}

The cool thing about iterators is that when a value is yielded to the caller, the method is effectively suspended – exactly what we want for our asynchronous programming.

In ProModel’s Core library, I have implemented some fairly simple interfaces, classes, and extension methods that leverage the iterator mechanism to make coroutines available for asynchronous programming.  All it takes is to wrap an asynchronous method in a new class that implements the IProcess interface.  Then, you can even create some helper methods that can make our data incrementing example as simple as this:

public IEnumerable<IProcess> IncrementData()
{
var dm = new DataManager();
yield return dm.Load();
dm.Data = dm.Data + 1;
yield return dm.Save();
}

Now that’s more like it – simple, sequential, readable, and maintainable.  One last little bit, though.  Whoever is calling the IncrementData method needs to do it in a slightly special way.  Let’s say we increment the data when the user clicks a button.  An extension method in our Coroutines library, Enumerate, makes it very simple to kick off our new coroutine:

public void OnButtonClick(object sender, EventArgs e)
{
IncrementData().Enumerate();
}

And that’s pretty much it.  It can take a little time to get used to coroutines, but they are well worth it.

Various implementations of coroutines using iterators can be found on the internet (such as in the Caliburn project).  However, I decided to write our own implementation for use in our Core library for a few of reasons:

  • I wasn’t satisfied with some of the naming.
  • I didn’t see any simple solutions to the issue of calling coroutines from other coroutines, which I solved myself.
  • The implementation is really quite simple, that writing our own took very little time and allows us to implement and expand the constructs in a manner that is consistent and makes sense for ProModel development.

While the iterator implementation of coroutines makes asynchronous programming far better, it can still be a bit wordy, what with all the IEnumerable<IProcess>’s and yield return’s.  Fortunately, Microsoft has since recognized the general pain of asynchronous programming and in .NET 4.5 introduced an even cleaner solution, with built-in language support – the wonderful async/await pattern.  This new pattern effectively renders our custom implementation obsolete and even solves some of its limitations.  However, this is a discussion for another time.

Advertisements

Author: Dan Hickman

Chief Technology Officer ProModel Corporation

One thought on “ProModel Coroutines (prior to async/await pattern)

  1. Thanks Terry… I even think I understood some of that!…

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s