I need to get some stuff sorted out about all this async stuff.
Let’s say I want to load a big file. From my understanding there is a difference in just calling File.Read() and queuing this up into the thread pool or using the Begin-/EndRead API.
As far as I know, if you use the BeginFoo/EndFoo API you are not even blocking any thread but instead the hardware will just call you back whenever it has finished it’s work. By contrast, spinning up a thread from the ThreadPool means you are at least blocking this particular thread for work that is actually not CPU related…
So far, so good.
I wonder what does the task library actually do if I use File.Read? Is it smart enough to change my code to use the BeginFoo/EndFoo API? Or will it just spin up a thread from the ThreadPool?
If it’s really changing my code, I wonder how far will it hunt down my code to rewrite method calls?
Does that make any sense?
Help me out please!
You say you wonder if “the task library” changes your code. There are two distinct pieces – the Task Parallel Library (which is available today having shipped in .NET 4.0), and the new C# async stuff, which will ship with C# v5.
The C# async stuff itself is split into two things: compiler features and an accompanying library. It’s not entirely clear what will be in the library when it finally ships – today, they’ve put some extension methods in there that add methods to
Taskand a few other existing class library types (e.g.,WebClient) to make them work smoothly with the new compiler features. Some of the things in this C#-specific library that ships today may well become part of the .NET Framework Class library when C# 5 finally ships. However, it’s currently looking likely that there will also be some stuff that may not belong in the main framework class library, but some of that might move into a support DLL like the one you have to use if you wantdynamictoday.So, with that background, it should be clear that the task library will never rewrite your code, because it’s already there today, and it’s just a library.
The compiler will rewrite your code, but it mainly does it the same way that iterators do today: it’ll take what looks like one sequential method and split it up into several methods, adding some state tracking to enable the method to pick up from where it left off.
The compiler won’t replace a
Readwith aBeginRead. In fact C# 5 doesn’t even know anything about the Asynchronous Programming Model. (The APM is the official name for theBeginFoo/EndFoopattern.) C# 5 demands a very specific pattern when using theawaitkeyword that doesn’t look quite like any of the asynchronous patterns that are around today, which is why the async preview ships with a library that provides extension methods forTask– it adds in the methods that C#5 expects.(So just to be clear, C# 5 doesn’t have any special handling for
Taskwhen it comes to consuming asynchronous operations. On the contrary, the async preview has had to bolt on some additional methods toTaskjust to make it work. That said, C# 5 does have special handling forTaskon the provider side of things – it is able to generate code that creates a newTaskas the return value of anasyncmethod. But since your question is about consuming asynchronous features, that’s not directly relevant here.)Specifically, C#5 will expect the expression following the
awaitkeyword to evaluate to something that you can invoke aGetAwaitermethod on. (It doesn’t care whether that method is provided by the object/struct the expression evaluates to, or provided by an extension method.) The thing returned byGetAwaitermust offer two methods:BeginAwaitandEndAwait.Those are the only method calls that C# 5 will add to your code as it transforms it to support
async/await. Furthermore, it won’t change any method calls already in your code – so if you already call some method, say,Read, it won’t get rid of that or replace it. It only adds to what you already wrote.The relationship between C# 5 the APM (
Begin/EndXxx) is rather at arms length. The way you consume the APM is that you first wrap the APM work in aTask(which you can already do today in .NET 4, using the various overloads of theTask.Factory.FromAsyncmethod), and then you rely on the extension methods that enable aTaskto be consumed by theawaitkeyword.