This month’s issue of MSDN Magazine includes three feature articles covering the new asynchronous programming features coming to C# and Visual Basic in .NET Framework 4.5. Mads Torgersen, principal program manager on the C# and Visual Basic Language team at Microsoft, is the author of one of those features (“Pause and Play with Await“), which explores the workings of the new functionality. I asked Torgersen a few questions about the technology and how developers can best prepare to take advantage of it.
Michael Desmond: How complex a task was it to actually add Async functionality? I’m guessing that there is a lot going on in the compiler, and that you’d have to architect it to manage a lot of scenarios.
Mads Torgersen: It was quite complex in the details, and became even more so as we put in work to optimize performance, but the core implementation approach is quite simple. The essential challenge is to be able to pause and resume execution of a given piece of code in mid-flight. Instead of chopping up the generated code into separate bits, we use a technique (that was prototyped with the Axum project) where we “parachute in” to the right place in the user’s code — using goto’s!
It’s a rock solid strategy because we don’t change the structure of the original source code — only embellish it a bit. As we’ve extensively tested correspondence between sync and async code, we’ve been confirmed that this works great. We’ve had a surprisingly small bug tail of inconsistencies.
MD: Related question: Can you describe a significant or particularly interesting challenge your team faced in implementing Async, and how you ultimately managed to work through it?
MT: The issue we call “stack spilling” was hard to get right. Execution may get suspended in the middle of the evaluation of an expression, and the parts already evaluated need to get squirreled away for when execution resumes. That proved to be difficult, especially because some temporary results (such as a reference to an array element that you are about to assign to) cannot be stored in an object on the heap. Instead we need to “back up” and store the constituent parts (like the array reference and the index) to simulate that it has been evaluated, when in fact it hasn’t.
Another tricky area has been making sure there are no race conditions between suspension and resumption, especially because resumption involves calling into user defined code.
MD: Whenever a significant feature addition occurs to a programming language, it perks my interest. There is always a strategic push and pull, as teams must weigh the benefit of new features against the dangers of bloat. Did this issue play into the discussion of adding async and, if so, how did it impact the implementation?
MT: We are always worried about bloating the languages, because we can add but never take away. For something like async there was no doubt it was worth its weight, but we still took great care to minimize the syntactic footprint of the feature. There are two new keywords, and believe me, each one was discussed for weeks on end — is it really necessary and what should it look like!
On the library side there is a different situation, because we are introducing a new asynchronous pattern to the framework and there is a lot of “duplication” needed for existing asynchronous methods to be offered in such a new version. Ultimately, we all decided that it was worth the bloat. It is easier to live with legacy in libraries than language, and the new shape really is a huge benefit to API consumers.
MD: With multi- and many-core systems now the norm and cloud-based applications taking off, Async seems like a strategically important addition to the .NET language toolbox. You get the feeling that you are showing up with this functionality in the nick of time?
MT: I think that is very true. We already introduced the Task types in .NET 4 to raise the level of abstraction for parallel programming, but with async we elevate Tasks to a much needed unifying role that helps coordinate the many kinds of simultaneous activity you can have in a modern-day application in a uniform manner. I think this common abstraction at the API level, combined with the language support for its composition, will prove to be a tremendous foundation for developers as we grow further into the cloud and device spaces in the coming years. I am really excited that we’ve managed to rally so beautifully around one simple core concept here.
MD: Obviously the Async bits are out there for developers to work with. But beyond working with the available pre-release tools, what can developers do to prepare themselves, and their applications, for asynchronous development?
MT: Become Task-based! Even on .NET 4 the Task types are a much better currency for asynchronous activity that the older patterns we have. You still need to be callback-based because you don’t have the language support, but in a more elegant way. And having all your signatures follow the new Task-based pattern will prepare you beautifully for the day when you can consume those with just a simple “await” expression.