Refactorings to execute statements asynchronously
In continuing with the ‘Refactorings for simplifying of the .NET 4.0 parallel computing development‘ thread, let’s review the additional refactoring for executing statements asynchronously called in the same manner – Execute Statement Asynchronously. The refactoring is available in two versions:
- Execute Statement Asynchronously (FromAsync)
- Execute Statement Asynchronously (StartNew)
The FromAsync version of the refactoring launches an asynchronous operation passing a pair of the corresponding BeginXxx and EndXxx methods of the selected statement to the FromAsync call of the Task.Factory. The FromAsync call provides a convenient mechanism which uses the BeginXxx and EndXxx methods of the Asynchronous Programming Model (APM) to create a Task.
The TaskFactory simplifies creation and startup of simple background tasks dramatically. For example, consider that we have a Stream and a byte buffer, and we want to read from that stream into the buffer. Synchronously, we could do the following:
The Execute Statement Asynchronously (FromAsync) refactoring will allow us to convert this code into the FromAsync call:
resulting in the following one:
The FromAsync call returns a handle to the associated Task. The resulting Task object will, by default, be executed on a thread pool thread. Combine this support with the ability to do Task.WaitAll, Task.WaitAny, Task.Factory.ContinueWhenAll, and Task.Factory.ContinueWhenAny, and we can achieve a very useful synchronization functionality having just a little code.
The second version of the refactoring (StartNew) launches an asynchronous operation by passing the current statement to the StartNew method of Task.Factory. For instance, using StartNew is more efficient than creating and starting tasks manually, because the StartNew method not only starts a new task but also applies the required synchronization to the process. If you construct a task using the Task’s constructor, you then pay this synchronization cost when calling the Start method, because you need to have protection against the chance that another thread is concurrently calling Start. However, if we use the Task.Factory.StartNew, we know that the task will have already been scheduled and started by the time we get the Task reference returned, which means that it is no longer possible for threads to race to call Start, because every call to Start will fail. In the case of using StartNew, we can avoid the additional synchronization and take a faster and easier approach for scheduling a Task.
The Execute Statement Asynchronously (StartNew) refactoring can be applied on any statement:
which will result in:
The difference between the StartNew and FromAsync methods is that using the latter for the things like Stream (i.e., when API offers the appropriate BeginXxx and EndXxx methods), you will actually end up using the async I/O underneath the covers, e.g., I/O Completion Ports in Windows which provide an efficient threading model for processing multiple asynchronous I/O requests on a multiprocessor system. The FromAsync method in this case provides the best way to achieve I/O scalability, and is more efficient than blocking multiple CPU threads doing a synchronous operation using the StartNew method.—– Products: CodeRush Pro Versions: 12.1 and up VS IDEs: 2008 and up Updated: Sep/17/2012 ID: R069