Archive for the ‘API Team (Red)’ Category
MindTouch Coroutines and C#5.0 async
This week, at PDC 2010, Anders Hejlsberg introduced what is to become C# 5.0 and it’s major new feature: Making Async easy. The main facility for achieving this goal is the language keyword pair or async and await. Together they allow synchronous methods to be called in an asynchronous way without having to jump through all sorts of hoops.
This is very exciting stuff for us here at MindTouch, since we’ve built almost exactly that facility with our Asynchronous Method Pattern and Coroutine infrastructure in DReAM. But the one thing that has always bothered us what the additional manual code and sometimes unintuitive syntax required.
The Result and Task based asynchronous patterns
Steve Bjorg introduced Result<T> with DReAM on top of the .NET 2.0 and mono 1.1.16 back in 2006. You can find a quick overview of it here. I've also covered it extensively in my monoconf talk. It's is similar in purpose to the Task class in the Task Parallel Library introduced by Microsoft in .NET 4.0. Both of them are a kind of future, a handle for a value that may or may not have been produced yet. Both provide asynchrony patterns for easily calling a method that promises to produce a result eventually.
The MindTouch Asynchronous Method Pattern (AMP) takes this form:
Result<T> MethodName(...input paramaters..., Result<T> result)
where the trailing Result<T> is used to set up conditions on the return value, such as Timeout.
The Task-based Asynchronous Pattern (TAP) looks like this:
Task<T> MethodNameAsync(...input paramaters...)
Both are easy enough to call in blocking form, but that defeats their purpose. Both could also be set up with continuation handles, which get executed once a value T is available, but that takes the return code out of the current flow. And as completions call other asynchronous methods, your code just wanders off the right-hand side of the screen. This is common problem with continuations and is both a aesthetic and readability problem, in that your logically linear (if non-blocking) execution flow becomes increasingly difficult to follow.
Simplifying async flow with MindTouch Coroutines
What would be really nice is being able to call an asynchronous method and write the code that deals with the result on the next line, while simultaneously having your code suspend itself, freeing up your thread while the asynchronous code completes.
One way to approach this is with coroutines, i.e. a method that can exit and resume multiple times, rather having only one entry point. A coroutine can yield control to the async method and resume after it completes. In .NET 2.0 the yield operator was added to C# for the iterator pattern. If you turn the iterator pattern upside down, you end up with a method that yields not iteration results but continuations to some engine executing the control flow, i.e. MindTouch Coroutines:
Result<XDoc> r; yield return r = Download(uri, new Result<XDoc>); var doc = r.Value;
This provided us with the ability to write methods in synchronous style that could call to potentially long running asynchronous processes but continue their linear flow without ever blocking the thread. For a more detailed look at how coroutines are implemented check this article. However, the cost of achieving this came with some syntactic artifacts.
As illustrated above, we can't declare and assign the result type T in the yield return, hence the pre-declaration of Result<XDoc> r and the trailing var doc = r.Value. Three lines instead of one. In C# 3.0, using Lambdas, we reduced this to two lines:
XDoc doc; yield return doc = DownloadAndProcess(uri, new Result<XDoc>).Set(v => doc = v);
Another artifact is that a coroutine has to return an enumerator. We use IYield, which Result implements and coroutines require the return type IEnumerator<IYield> and by convention use a Result<T> as their last argument. That means coroutines can yield AMPs but are not AMPs themselves. As I stated above, a coroutine is an iterator turned upside down, yielding control to some executing engine. This means that every AMP that uses a coroutine can be written using this convention:
Result<XDoc> DownloadAndProcess(XUri uri, Result<XDoc> result) {
return Coroutine.Invoke(DownloadAndProcess_Coroutine, uri, result);
}
IEnumerator<IYield> DownloadAndProcess_Coroutine(XUri uri, Result<XDoc> result) {
XDoc doc;
yield return Plug.New(uri).Get(new Result<DreamMessage>)
.Set(v => doc = v.ToDocument());
// do some more async work
result.Return(doc);
}
Note: I snuck in Plug here, which is our fluent interface wrapper around HttpWebRequest and implements the AMP, internally using the async interface of HttpWebRequest, i.e. we can yield a Plug.Get and it will resume execution once the request completes.
C# 5.0 async/wait continuation flow
With C# vNext, Microsoft introduces two new language keywords that basically let you create the same flow we provide via the AMP and Coroutines, but using Task and leaving the syntactic cost to the compiler instead. This means that the TAP can be used without having to define a custom method with a different signature to execute the async work flow:
async Task<XDoc> DownloadAndProcess(XUri uri) {
var doc = await Plug.New(uri).Get();
// do some more async work
return doc;
}
The async keyword marks the method as one that the compiler needs to rewrite a sequence of continuations. The await keyword tells the compiler that a TAP method is being called and to squirrel the rest of the method body into a continuation that is executed once the Task<XDoc> has a result. Here the compiler takes on the work of letting you use a single method signature to call either as a regular method or as source of a continuation and rewrites a TAP call to yield execution flow and resume after completion. Using async/await certainly reduces ceremony and makes it all more readable. We wish we could have had that luxury when we embarked on this pattern 4 years ago. Note: The above code pre-supposes a version of Plug that implements the TAP instead of the AMP.
yield vs. await vs. something else
Shortly after Anders' PDC talk Eric Lippert posed the question whether await is the best name for this new facility in the post Asynchronous Programming in C# 5.0 part two: Whence await? on his blog. The comment thread is a good read of arguments for and against various keywords. Personally being partial to yield, I read Jon Skeet's case against it in his post C# 5 async and choosing terminology: why I'm against "yield" with interest. His point is that "[w]hen the action completes very quickly and synchronously, it isn't yielding at all." My personal feeling is that whether or not the call returns very quickly is an implementation detail invisible to the caller. The caller is yielding control to the callee, who makes the decision whether to return immediately or suspend the caller until completion.
However await does seem like the least appropriate of the options, since we're really not waiting at all. Syntax like continue after, continue with and continue when certainly seem more appropriate and descriptive of the action taking place. While yield return perfectly describes to me what happens, maybe that is a sign the terminology reveals the implementation detail rather than the intent. The caller doesn't care about the yielding of control. The caller just wants the result from the call and get on with its business. So from a clarity of code perspective, I have to side with the continue (after|with|when) camp.
When can I use async/await?
The CTP is available now. Of course, there is no release date, taking a gaming industry "when it's done!" stance. My bet is that async/await will be usable in the next mono release (2.10? 3.0?) before C# 5.0 ships. Any way you look at it, though, it's going to be a while before you can rely on it existing on a platform you didn't personally configure.
In the meantime, DReAM coroutines are battle tested, powering all REST services in the MindTouch product and any other product using DReAM, and you can be sure that as C#5 approaches we will be tracking its progress closely to evaluate using the TAP in DReAM. We certainly would love to take advantage of the simplified syntax, while staying compatible with our existing syntax.
Generate .NET documentation with MindTouch 2010
If you write .NET code consumed by others, you are undoubtedly familiar with the inline XML documentation markup available. It’s a fairly simple embedded documentation syntax for which Visual Studio even provides some Intellisense and compile time checking. It keeps documentation and signature meta-data that can be derived from the code separate to avoid drift between code and documentation as much as possible.
Most developers initially start using it to provide Intellisense support for their code. But sooner or later most will want to publish the documentation as a reference document for their APIs. This would seem like the ideal use case of the mark-up format, but once you starting looking at the available tools, most developers find them lacking. Originally, NDoc provided the equivalent documentation generation that javadoc provides to developers on the Java side. Unfortunately NDoc was discontinued before .NET 2.0. In its place there exist Microsoft’s Sandcastle and mono’s monodoc. And now mindtouch.doc has been added to that list.
The goal of mindtouch.doc was to generate hierarchical reference documentation that could easily be imported into an MindTouch install. Unlike the standalone documentation generated by other tools, documentation imported into MindTouch can be easily extended by the extensive authoring and curation capabilities of MindTouch, such as IDF. Instead of just statically generated reference documentation, documentation in MindTouch can be tagged, linked, mashed-up with all your other documentation, tutorials, etc., including the ability to involve your community in the further growth of your documentation.
Authoring
We created mindtouch.doc to generate documentation for the DReAM Framework to be hosted on developer.mindtouch.com. The first task was to document all public classes in the framework using the .NET Xml comment docs:
With this in place, Visual Studio generates an XML document containing the meta-data from those comments. Using mindtouch.doc.exe, the code Assemblies along with their Documentation XML were converted into MindTouch import archives and imported into the site to produce documentation like this:
You can take a look at the MindTouch DReAM reference documentation to explore the entire generated documentation.
In addition to generating individual pages for each class, separate pages with Constructor, Property, Method and Event details are generates as child pages, along with Table of Content pages by Namespace and Assembly.
mindtouch.doc can generate documentation for an unlimited number of Assemblies at once. When the code to be documented is analyzed any references to any any class or member mentioned in the same or another assembly generates links between the relevant pages.
Since all content is imported as pages into MindTouch, you also get full revision history of past documentation imports (if the content has changed), so that documentation of newly added classes just requires a fresh import on top of the existing documentation.
Importing .NET documentation
If you want to try out the process, but don’t have documented code handy, you can import the DReAM documentation into your own MindTouch instance with the following command:
mindtouch.doc.exe -h mydomain.com -I ref/Dream mindtouch.dream.dll mindtouch.core.dll
This will prompt you for your user and password and import the documentation in ref/Dream.
The generated documentation has an external dependency on a template called DocToc. The purpose of this template is to allow simple Table of content customization using DekiScript and to make it easy to include custom css for documentation pages. The generated documentation HTML uses minimal markup along with classes to provide the greatest customization flexibility. The version of DocToc we use on developer.mindtouch.com simply looks like this:
<table style="background-color:#F9F9F9; border:1px solid #AAAAAA; font-size:95%; padding:5px;">
<tbody>
<tr>
<td>
<div align="center"><strong>Table of Contents</strong></div>
{{ page.toc }}
</td>
</tr>
</tbody>
</table>
Shipping your documentation
mindtouch.doc allows to directly import the generated documentation or to save the generated output as a MindTouch archive (.mtarc) which you can provide to customers to import into their own MindTouch installs. This is a regular MindTouch archive, the same that you would use to package up other documentation, scripts and templates authored in MindTouch. It can be imported via the Desktop Adapter or mindtouch.import.exe.
Documentation generation tool details
Running mindtouch.doc.exe without any arguments produces the following help output:
MindTouch Documentation, Copyright (c) 2010 MindTouch Inc. USAGE: mindtouch.doc.exe [options] [assembly1 .. assemblyN] Options: (Options must be prefixed by a '-' or '/') General: ?|usage - display this message h|host <host> - MindTouch host (assumes standard API location) u|uri <api-uri> - specify the full uri to the API (instead of using <host>) I|importreltopath <path> - relative uri path for import importrelto <id> - relative page id for import (alternative to importreltopath) o|output - output path for generated documentation (will skip import) R|retries - Maximum number of retries on import/export item failures (default: 3) Authentication: (if no authentication is provided, the program will prompt for user and password interactively) A|authtoken <token> - authtoken to use for user authentication U|user <username> - username for authentication (requires password option P|password <password> - password for username authentcation
The official documentation can be found on developer.mindtouch.com.
mindtouch.doc offers an easy way to take your documented .NET APIs and publish them with the power of MindTouch, no separate runtime or site required.
A pattern for modifying method behavior by an unknown party
I’m currently doing some experimental work towards what i’m tentatively calling DReAM 3.0. I’ve got some ideas for additions and changes and welcome any and all feedback. A primary focus for this release is to make Dream more approachable and easier to use. Mind you, this is speculative work and nothing on that page nor mentioned in this post is set in stone yet.
Last night I was dealing with splitting up some DReAM functionality into client and server assemblies and running into a consistent pattern where certain classes have augmented behavior when running in the server context instead of the client context. Since the client assembly is used by the server assembly, and these classes are part of the client assembly, they do not even know about the concept of the server context. Which leads me to the dilemma, how do I inject different behavior into these classes when they run under the server context?
I originally posted this on my personal blog as a late night rambling about a solution I came up with, but wasn’t particularly enamored with, hoping to see if there was an obvious pattern or facility I was overlooking. Since then @jongalloway suggested on twitter that I look into using MEF. Since DReAM already does assembly discovery in a number of places, I’ve been meaning to look at MEF to replace that hand-rolled reflection code. So this might be the final nudge.
This is one way to do it…
Let’s assume that the server context can be discovered by static means (i.e. a static singleton accessor) which also lives in the server assembly. To let this context inject its behavior, I’ve extracted the affected behavior into an interface and use discovery to build a chain of implementations to handle the behavior. A sample interface might look like this:
public interface IFooHandler {
ushort Priority { get; }
bool TryFoo(string input, out string output);
}
TryFoo gives the handler implementation a chance to look at the inputs and decide whether to handle or pass on it. The handler chain is used with this linq expression:
public string Foo(string input) {
string output = null;
_handlers.Where(x => x.TryFoo(input, out output)).First();
return output;
}
This assumes that _handlers is sorted by priority. The method returns the result of the first handler to report true on invocation. Building up the _handlers happens in the static constructor:
static Bar() {
_handlers = typeof(IFooHandler)
.DiscoverImplementors()
.Instantiate()
.Cast<IFooHandler>()
.OrderBy(x => x.Priority)
.ToArray();
}
where DiscoverImplementors and Instantiate are extension methods i’ll leave as an exercise to the reader.
Now the server assembly simply creates its implementation of IFooHandler, gives it a higher priority and on invocation checks its static accessor to see if it’s running in the server context and if not, lets the chain fall through to the next (likely the default) implementation.
Looking for alternatives
I’m about to do a deep dive into MEF to see how it can help. Whether it’ll just take over the discovery of handlers for the chain or has a way to better deal with the injection of the behavior as well, I don’t know yet. I’m of course open to other solutions as well.
Serialization, Cloning and Immutability
Sparked by a discussion I had with Steve, I started looking at mechanisms for safely passing data between tasks with the emphasis on neither side ever seeing changes made to the data. This led to (currently) three blog posts on my personal blog, this being work that is more of an exploration and not yet something planned for inclusion in Dream.
The first post “Sharing data without sharing data state” reviewed patterns for sharing, from cloning to immutability to serialization and finally introduced a pattern for freezing objects in .NET. I followed this up with an implementation of a “Freezer” to automatically attach IFreezable behavior to Data Transfer Objects (DTOs), AOP style. This work was described in “Freezing DTOs by proxy” and the project, Subzero, can be found at github. The initial implementation used serialization for cloning objects as required when no Clone() method could be found on the DTO.
Next I decided to write a generic cloner for Subzero, based on my premise that serialization is expensive. This turned out to be a lesson in measuring and optimizing. My first pass was only faster than .NET’s built in serializer, BinaryFormatter, and being slower than BinaryFormatter can only be achieved by copying things to pager and typing it back in by hand. Other serializers blew my cloning out of the water. “When cloning isn’t faster than copy via serializer” describes the work of optimizing the cloner and comparisons to various serializers.
Dream 2.0 introduced the IKeyValueCache with an in-memory implementation and a plan for a Memcache wrapper. This cache uses serialization by default and let’s you easily register your favorite serializer. We’re using this cache in MindTouch Core for optimizing search performance and may use it for the MindTouch Platform data caching layer, which currently does explicit copying of entities in and out of the cache. So it would make sense to revisit IKeyValueCache and have it take advantage of IFreezable to avoid copying when possible and use Incubator.Clone when unavoidable to reduce all the manually maintained copy code.
Subzero may eventually make it into Dream, both for caching and potentially for Dream in-process REST calls, but we’ll have to see what makes sense. For right now Subzero is more an infrastructure experiment we’re evaluating for use.
Read() vs. Peek(): when -1 != -1
I just got through an elaborate debug session trying to find a sneaky parsing problem with incoming Http POST requests that happened:
- intermittently (every 500-2000 iterations), and
- even in intermittent form was only reproducible (outside of the client production install) on a VM running on Corey’s laptop
Copying the VM to my machine or another VMware server would stop it from occuring at all, no matter how many iterations. At least this ruled out a bad binary, runtime version and environmental config issues.
I narrowed the problem down to occasional premature end of stream issues, i.e. less bytes were read than sent. The fun thing with debugging Streams is that by the time you find out a problem occurred, the debugger is useless. So I wrote a Stream wrapper that recorded each bytes as it came in.
This identified our TrimmingTextReader‘s Read() implementation as sometimes returning -1 before the end of the stream. The TrimmingTextReader is a wrapper around a normal TextReader that trims leading and trailing whitespace as it reads the stream without having to allocate the full string first.
Double-checking MSDN, i confirmed that TextReader.Read() should return “[t]he next character from the input stream, or -1 if no more characters are available“. Our implemenation of Read() had an optimization of using Peak() to check the next byte for whitespace and read it into our whitespace buffer, otherwise return the next character from the whitespace buffer instead:
// accumulate whitespace characters until we determine
// if we have reached the end of the reader or not
for( ch = _original.Peek();
(ch >= 0) && char.IsWhiteSpace((char)ch);
ch = _original.Peek()
) {
_buffer.Append((char)_original.Read());
}
The documentation for Peak() states that it returns “[a]n integer representing the next character to be read, or -1 if no more characters are available“. Essentially the same wording, except further down there was this caveat: “The Peek method returns an integer value in order to determine whether the end of the file, or another error has occurred.” Get that? End of file, or another error! But if i just did Read() it happily returned the next character, so what was this error that Peak() seemed to be detecting?
StreamReader reads bytes from the underlying stream in chunks:
var read = int Read(int[] buffer, int offset, int count)
In the failed request scenario, the Stream.Read call had returned less read bytes than requested in count, a perfectly valid response. Only if read is 0 has the end of stream been reached. But Peek() does not trigger another read from the Stream, while Read() will. This means that, Peek() will report -1 if the next byte it looks at isn’t in current buffer, since it’s at an index larger than read.
So, aside from being ill-documented behavior of two seemingly analogous calls, this behavior is also incredibly useless: You can keep calling Peek() over and over and keep getting -1 and never know whether it’s really the end of the stream or just some error. Only a Read() will tell the difference between the two scenarios. Of course, this is simply a lesson in “don’t assume anything“, but I hope that my debugging session will help someone avoid the tedious path of discovery to this bit of knowledge.




