The Task<T> class was integrated with the .NET Framework in .NET 4.0, as part of what is known as the Task Parallel Library. The main purpose of the TPL was to facilitate writing parallel code, making it easier to run code on multiple cores, for instance. That is why the class itself was called Task, it represented a piece of program you could run in parallel with other pieces of program. Task, however, is much more versatile than that. In .NET 4.5 (now RTM, and on MSDN next week), Task will be the primary actor for working with the new async/await language feature.
What Task is in reality is a “future”. A future is an object that represents a value which may or may not exist yet. When you run a piece of code using Task.Run, what the Task returned represents is the return value of your piece of code. It will only be available when the piece of code finished running. However, Task is suited to represent any sort of operation that hasn’t completed yet, parallel computation but also IO. If parallel computing is important in some fields, asynchronous IO is capital for almost any application (Client and server).
Reactive Extensions (Rx) is a project that was started by Erik Meijer before the TPL even existed. It was only released recently though (2010). Rx is providing a new interface (IObservable<T>) that can be combined by the means of operators, the same way you can use LINQ on IEnumerable<T>.
Historically, the async/await feature did not exist yet when the Rx project started. As a result, they have now a great deal of overlap in what they can do. It doesn’t mean that one must disappear, there are situations where one or the other will be better suited. Let’s now see which one is better suited for what.
Let’s say you are turning a synchronous function returning int to async, you could do two things: return IObservable<int> or Task<int>.
Rx provides you with a bunch of operators, one of them is Observable.Return. This returns an observable that pushes a single value, then completes immediately. My opinion is that returning Task<int> is better, and here are the reasons why:
As you saw in the previous section, Task is a better abstraction and easier to reason with, but there are situations where Task<T> is not the best tool for the job. Task<T> represents a future for a single value of type T. Sometimes, you need to return a stream of values. Here is an example: let’s imagine you are writing an asynchronous function that reads a database table, and returns it. If you return task, you will have to return something like Task<List<Row>>, that means you will be buffering all the rows in memory, and complete the task when the whole table is buffered. You can probably see why this can become a scalability issue. A better option is to return IObservable<Row>. Each row, as it is read from the database, is pushed through the IObservable. The consumer can then process rows as they become available, and there is never more than one row in memory at the same time.
Note that if as a consumer, you still want to buffer all the rows, you can easily convert the IObservable<Row> to a Task<IList<Row>>, using this function:
public static Task<IList<T>> BufferAllAsync<T>(this IObservable<T> observable)
List<T> result = new List<T>();
object gate = new object();
TaskCompletionSource<IList<T>> finalTask = new TaskCompletionSource<IList<T>>();
exception => finalTask.TrySetException(exception),
() => finalTask.SetResult(result.AsReadOnly())
To wrap up, I would suggest to use Task whenever you can, and use IObservable if you get into a more complex situation where you need an entire collection to be turned asynchronous.