The advancement
in software technology is so rapid that it has necessitated the usage
of high-end processors for executing the complex logic involved in it.
It has also now become very common to execute code on multiple processors.
When all these have occurred in the hardware side, the software is also
geared to provide efficient code that can harness the maximum possible
performance of the processors. The concept of threading in software development
is about this aspect of improving the speed and efficiency of the software.
It helps to perform multiple operations simultaneously by utilizing the
idle time of the processor(s) to a great extent.
Asynchronous
programming is about executing part of code on separate threads. A thread
is a sequence of execution in program. The .Net framework has implemented
the feature of asynchronous programming through the Asynchronous Programming
(APM) Model by allowing to executing tasks in a non-linear way. It provides
rich set of classes implementing the asynchronous operations and prescribes
a standardized mechanism that can allow executing them without directly
working with the threads. With this, the application developed can perform
faster and better, be more responsive and utilize system resources optimally.
Different types of APM in .Net
The APM involves
executing an asynchronous operation by calling a method (starting with
Begin) with the relevant data. To control the execution of
this operation at its end stage, the terminating method (starting with
End) is called in different ways.
For example,
the method, BeginRead () and EndRead () of the FileStream class is used
to read the bytes of a file asynchronously. While initiating the asynchronous
call, an object of type, IASyncResult is returned with values filled with
relevant information. The same IAysncResult object is also passed as parameter
to the method called during the termination of the asynchronous method.
Based on
the way in which the end of the asynchronous call is handled in the code,
the .Net framework has classified three styles of APM as listed below:
Wait-until-Done
model:
This model is used when the application cannot execute any additional
work until the results of the asynchronous operation is received. The
asynchronous operation is initiated by the call to BeginOperation.
By calling the method, EndOperation (method corresponding
to the asynchronous version of the termination of actual operation) in
the main thread, further execution of application is blocked. The time
between these two calls can be used to execute any other task. In this
method, the IASyncResult instance returned from the call, BeginOperation
is passed as parameter to the EndOperation.
Polling
model:
In this model, the status of execution of the asynchronous task is polled
at regular time intervals (for example, in each iteration of a loop).
During the time interval, some other tasks can get executed concurrently
in the main thread. But, only after the completion of the execution of
the asynchronous task, further execution takes place in the main thread.
The completion status of execution of the asynchronous operation is updated
in the IsCompleted property of the IAsyncResult object returned from the
EndOperation method. Hence, this model allows executing the
tasks in main thread by polling on the status of completion of the asynchronous
operation.
Callback
model:
This model uses an AsyncCallback delegate that is created and passed as
parameter to the BeginOperation method. This will in turn
allow the delegate to be called at the end of execution of the asynchronous
operation executing on another thread. Also, any state information (like
file handle, status flags, etc.) required during the termination of the
asynchronous operation is passed through this callback method. This model
allows the execution of asynchronous operation in a fire and forget
kind of state wherein the termination occurs in a different code.
Helper classes for APM
Some of the
helper classes designed to aid APM are ThreadPool and Timer included in
the System.Threading namespace. ThreadPool is used for getting a thread
(already instantiated and maintained by the framework) from a pool of
threads for performing asynchronous programming. The main aim of using
ThreadPool is that it saves time for the application since it reuses existing
threads without any setup tasks executed for the thread. Also, the code
size and hence the developing effort is greatly reduced since the thread
management tasks like creating, scheduling and termination are taken care
of by the framework itself.
Timer is
another important helper class used for creating periodically reoccurring
routines. Object of this class will fire an asynchronous call to a method
based on time. Options to specify the callback routine, time interval,
etc. can be specified during the creation of the Timer object.
Another class
called SynchronizationContext class is used usually to fire an asynchronous
call. This class provides two methods for asynchronous execution which
does not return any value or object. The Send method executes the asynchronous
code in a separate thread and also blocks the execution of the caller
until it returns. This is contrary to the method Post wherein the asynchronous
code is executed without blocking the execution of caller.
Tips:
Most of the classes supporting APM contain methods starting from
Begin and End. It is easier to identify such methods
for asynchronous operations. Example: BeginRead, EndRead, etc.
To handle exceptions (like InvalidOperationException) thrown during
asynchronous processing of a request, it has to be done at the time of
End call.
Since it is very difficult to troubleshoot multithreaded program(with
asynchronous code) due to the inconsistent behavior of the bug causing
error, it is suggested to carefully design proper threading technique
and incrementally develop the application so that it is more scalable
and robust.
Usage of Thread pool of the framework is highly recommended so
as to reduce the memory overhead caused due to the additional storage
of context information of the newly created thread.
While performance and responsiveness of the application is very vital
for the success of an application, it is also equally important to analyze
the pros and cons of usage of asynchronous programming in the development
of the software. It is found that the effort and time spent for using
asynchronous programming is worth for complex and time critical applications
having long running tasks rather an application of lesser complexity.