2011-09-16

Rx and Async

I saw some rather shocking tweets yesterday from the BUILD conference:


The author of that original tweet followed up with a blog post with some interesting Rx-related quotes from Anders Hejlsberg: "I don't know if we've decided [whether Rx will be included in future versions of .NET]." and "Personally I've found the stuff we've done with async allows you to do a lot more [than Rx]." (emphasis mine).

Interesting. I tried to take a listen for myself, but the Channel9 live interview was no longer available. Note that these remarks were made during a live interview, and were not part of a presentation; I'm hoping that Anders just answered off the cuff and didn't mean it.

One reason I found those quotes controversial is because parallel programming (TPL/PLINQ), background operations (async/await), and asynchronous streams (Rx) all address different problems. In particular, Async only supports background operations and does not support asynchronous streams. Rx supports both, but Async will become the default solution for background operations because it's easier to use than Rx.

So, I agree with Anders that Async is easier to use, but I totally disagree that Async is more powerful. Rx can do everything Async can do, and can do some things that Async can't do.

It comes down to the difference between asynchronous operations and asynchronous events. An asynchronous operation is something that my program can start, and it will complete some time later. An asynchronous event stream is something that is happening all the time independent of my program; it can subscribe and unsubscribe, but does not cause the events. This is an important distinction if you consider an event stream that produces in quick bursts (e.g., mouse movement); Rx allows collating all of those events, but an async-based solution may miss some (because it has to restart the operation each time it completes).

Historically, asynchronous events have been a blind spot for Microsoft. Consider a condensed history of asynchronous support:

  1. Asynchronous Programming Model (APM). In the beginning, there was only IAsyncResult (Begin/End). The APM was everywhere, even baked into delegate types. The thing to note about APM is that it is purely an asynchronous operation; no asynchronous events are supported. The program starts the operation, which has a single point of completion.
  2. Event-Based Asynchronous Pattern (EAP). Way back in .NET 2.0, the EAP was introduced. EAP works by capturing the current SynchronizationContext and then raising events on that context. This was the first asynchronous pattern that supported both asynchronous operations and asynchronous events. Unfortunately, the documentation assumed that EAP objects are only implementing asynchronous operations, and completely ignored the EAP support for asynchronous events. In addition, the most famous EAP implementation (BackgroundWorker) was just an asynchronous operation. However, the Nito.Async library included some helpers for EAP components, and included sample socket components using EAP in an asynchronous event fashion.
  3. Rx. Supporting .NET 3.5 and up, the Rx libraries are all about asynchronous events (and they also support asynchronous operations, which are just a singleton asynchronous event). Rx is also more powerful than EAP because it has a very flexible execution context, while EAP ties everything through a single SynchronizationContext. However, the learning curve for Rx is steep.
  4. Async/await and the Task-Based Asynchronous Pattern (TAP). These extensions to the language allow for a very natural and easy way to deal with asynchronous operations, but they do not support asynchronous events.

In terms of power and flexibility, TAP is approximately equivalent to APM (less powerful than EAP and Rx). The only reason it's a step forward is because it is so easy to learn and use. Some simple programs may use only TAP, but other programs will need both TAP and Rx.

Rx is a very welcome (and necessary) addition to our toolset. Async does not and can not replace it.

(P.S. All of this - and much more - is covered in my "Thread is Dead" talk, which has been submitted for consideration at a couple of conferences in the next few months. I'll update this space when it's accepted.)

5 comments:

  1. I actually remember him saying the other way, that Rx allowed you to do _more_ but that async is easier for the "background processing" scenario you mention.

    ReplyDelete
  2. Yeah, he didn't say anything that async can do more, for me it sounded like he actually said that RX might find its way to the standart .Net framework. Everyone is using it internally and I think both async and rx would work nicely together.

    ReplyDelete
  3. Stephen ClearySep 19, 2011 10:02 AM

    Thanks for the clarification! I only heard the last part of Anders live, so I totally missed this conversation.

    I think it would be a great idea to include Rx in the .NET framework.

    ReplyDelete
  4. nice post. 100% agree

    ReplyDelete
  5. The Akamai link to the interview are still up (at least at the time of this comment) http://smooth.akamai.istreamplanet.com/msft/build3/default.html

    ReplyDelete