For most .NET operations there is both a synchronous and an asynchronous way of
doing things. The problem is that these current patterns can prove disruptive
to program structure, leading to complex and error prone code or that developers
just give up and use the blocking approach, sacrificing UI responsiveness or
performance.
The goal of these new language features is to bring the asynchronous development
experience as close to the synchronous one as possible, without sacrificing the
ability to handle async-specific situations. The people at Microsoft understand
that asynchronous code blows up your control flow. The "call you back"
part needs a callback – a delegate describing what comes after. But the approach
is limiting. What if you wanted to "wait" inside a while loop, or
an if statement? You have a control - flow problem.
The new approach utilizes Tasks and two new keywords, async, and await. As a result,
your asynchronous code will now look virtually identical to its synchronous version,
with the compiler taking care of creating and signing up the callbacks.
An example from the CTP Whitepaper illustrates this new simplicity:
public async Task<int> SumPageSizesAsync(IList<Uri> uris) {
int total = 0;
foreach (var uri in uris) {
statusText.Text = string.Format("Found {0} bytes ...", total);
var data = await new WebClient().DownloadDataAsync(uri);
total += data.Length;
}
statusText.Text = string.Format("Found {0} bytes total", total);
return total;
}
What the above code does is to return a Task<int> which allows the caller to
use the returned Task<int> to inquire whether the work is complete, wait
for the int result synchronously or sign up callbacks to get it when it is ready.
This provides needed simplicity and also allows for a mindset which promotes
a more comprehensible control flow. The marking of the method with the async keyword means that the method body is compiled specially, allowing parts of it to
be turned into callbacks, and automatically creating the Task<int> that
is returned.
The "await" keyword in the var data = await new WebClient().DownloadDataAsync(uri); line looks like it is a blocking call, but it isn't. Instead it signs up the rest
of the method as a callback on the task, and immediately returns. When the awaited
task eventually completes, it will invoke that callback and thus resume the execution
of the method right where it left off.
The Task and Task<TResult> types are already in .NET Framework 4. A Task represents
an ongoing activity, which would usually be CPU intensive work running on a separate
thread, but it can also represent an I/O operation, for example waiting on a response
from a web request. Task by itself represents an activity without a result, and
Task<TResult>, represents an activity with a result of type TResult (in
the example case, an int representing the sum of all the page sizes).
The simplest implementation of use of the Task construct might look like this:
Task<double> task = Task.Run(() => LongRunningComputation(x, y, z));
This schedules the work represented in the lambda on a Threadpool thread, immediately
returning a task that will complete when the work is done. The caller can check
the Status, IsCompleted, and / or IsCanceled properties.
By returning a Task or Task<T> as in the Whitepaper example above, only one method is needed, and all further interaction
with the future result is done through the Task object.
Async methods by themselves do not run on their own thread. If you write an async
method without any await’s in it, it will be completely synchronous. Only when
an async method gets to the first await does it return to its original caller,
and only then until it await’s a task that is not yet complete. If you want to
get intensive work or blocking calls off your thread, you should explicitly put
them on the thread pool using Task.Run.
The AsyncCtpLibrary assembly has a new Type "TaskEx" with various methods
such as Run, Delay, RunEx, WhenAll, etc.
In Anders Hejlsberg's RSS Feed Aggregator sample (one of the samples in the CTP download), there are two different ways to get the feeds asynchronously:
// using parallel:
var feeds = new string[urls.Count];
Parallel.For(0, urls.Count, i => feeds[i] = CreateWebClient().DownloadString(urls[i]));
// using async:
var feeds = await TaskEx.WhenAll(from url in urls select CreateWebClient().DownloadStringTaskAsync(url));
Async methods can be explicitly written to be "fire and forget" – by returning
void instead of Task or Task<TResult> from the method.
The Task type also offers an easy way to get parallelism. With a collection of tasks,
you can call Task.WhenAll to obtain a task that completes when all of the constituent
tasks have completed. They will run concurrently and take advantage of multiple
cores.
You can download the Visual Studio Async CTP here:
It has a full suite of over two dozen samples in both C# and VB.NET including Silverlight,
WinForms, and WPF applications. There is even an options pricing example using
Excel.
In sum, The Visual Studio Async CTP combines a new simple and composable pattern
for asynchronous APIs, with "await" and "async" language
keywords in Visual Basic and C#, that avoids asynchronous code having to be written
"inside-out" using callbacks. The CTP is a painless install/uninstall
on top of Visual Studio 2010 RTM, and comes with plenty of samples and documentation. The
single AsyncCtpLibrary assembly is just 104Kb, and the Silverlight version only
132Kb. Recommended, because it's pretty likely you'll see this in C# 5.