Since the very first release of the .NET platform, programmers have been able to create multithreaded applications using the types of the System.Threading namespace. If you have worked with this API before, you might agree that while it is far easier to use than low level Win32 API and C plumbing, it was not always as seamless as one would hope.
As it turns out, one of the most common reasons a programmer would bother to manipulate threads in the first place was to keep a UI responsive during a long running operation. To achieve this, a programmer could opt to make use of the delegate type, which has built in support for asynchronous calls using a very well document ?IAsyncResult pattern?. This alone can simplify some threading issues, but yet again, the process is not as seamless as one might hope.
.NET 4.0 provided a third approach using the System.Threading.Tasks namespace (aka, the Task Parallel Library [TPL}) and the closely related PLINQ ParallelEnumerable.AsParallel() extension method. If you have looked at this new API, you might agree that Microsoft is certainly on the right track. Using the TPL / PLINQ, writing multithreaded / parallel apps is simpler than ever.
Now that the next version of the .NET platform is well under development, it is no surprise that Microsoft is looking for new ways to improve upon a good thing. One such update which should make the final cut is yet another way for developers to build highly responsive code using the new Async paradigm.
At its core, the Async model will grand C# and VB with some new keywords that can mark a method to be run asynchronously. However rather than forcing developers to manually spin up threads, delegates, callbacks (and so on), the compiler will do so when processing the appropriate async keyword(s).
If you are interested in looking at the current state of this new technology, here are some helpful links:
Once you have installed the Asnc CTP, you can navigate to your Documents folder and find a number of sample projects, additional whitepapers, and tutorials. Just to give a sample of the sort of code you can expect to be writing in the near future, the Async model allows you to replace rather grungy code such as this (the previous whitepaper explains the details of this code in some detail):
1: public void SumPageSizesAsync(IList<Uri> uris, Action<int, Exception> callback) {
2: SumPageSizesAsyncHelper(uris.GetEnumerator(), 0, callback);
3: }
4:
5: private void SumPageSizesAsyncHelper(IEnumerator<Uri> enumerator, int total,
6: Action<int, Exception> callback) {
7: try {
8: if (enumerator.MoveNext()) {
9: statusText.Text = string.Format("Found {0} bytes ...", total);
10: var client = new WebClient();
11: client.DownloadDataCompleted += (sender, e) => {
12: if (e.Error != null)
13: {
14: enumerator.Dispose();
15: callback(0, e.Error);
16: }
17: else SumPageSizesAsyncHelper(
18: enumerator, total + e.Result.Length, callback);
19: };
20: client.DownloadDataAsync(enumerator.Current);
21: }
22: else {
23: statusText.Text = string.Format("Found {0} bytes total", total);
24: enumerator.Dispose();
25: callback(total, null);
26: }
27: }
28: catch (Exception ex) {
29: enumerator.Dispose();
30: callback(0, ex);
31: }
32: }
With simple this:
1: public async Task<int> SumPageSizesAsync(IList<Uri> uris) {
2: int total = 0;
3: foreach (var uri in uris) {
4: statusText.Text = string.Format("Found {0} bytes ...", total);
5: var data = await new WebClient().DownloadDataAsync(uri);
6: total += data.Length;
7: }
8: statusText.Text = string.Format("Found {0} bytes total", total);
9: return total;
10: }
Obviously the new Async model provides a much cleaner, more compact model to achieve the same end result.
Happy coding!