Module 14 (Optional): Threading and Asynchronous Programming |
73 |
|
|
|
!Performance issues can result when a static method in a class calls a static method in the same class.
If these methods are not factored correctly, performance will suffer because there will be a large amount of redundant synchronization. Excessive use of synchronization may negatively affect performance. In addition, it may have a significant negative effect on scalability.
!Be aware of issues with the lock statement (SyncLock in Visual Basic).
It is tempting to use the lock statement to solve all threading problems. However, the System.Threading.Interlocked class is superior for updates that must be made automatically. It executes a single lock prefix if there is no contention.
In a code review, you should look for instances like the one shown in the following example.
lock(this)
{
myField++;
}
!Avoid the need for synchronization if possible.
For high traffic pathways, it is best to avoid synchronization. Sometimes you can adjust the algorithm to tolerate race conditions rather than eliminate them.
74 |
Module 14 (Optional): Threading and Asynchronous Programming |
" Asynchronous Programming in .NET
Topic Objective
To provide an overview of the topics that you will cover in this section.
Lead-in
In this section, we will look at how the .NET Framework enables asynchronous programming.
!Support for Asynchronous Programming in .NET
!Design Pattern for Asynchronous Programming
!Asynchronous File Stream Read Example
!Asynchronous Delegates
*****************************ILLEGAL FOR NON-TRAINER USE******************************
The central idea behind asynchronous programming is to be able to issue method calls to other components and to carry on with other work, without waiting for the operation to complete. The runtime provides rich support for asynchronous programming and handles the details of threading and data exchange.
In this section, you will learn about how the .NET Framework supports asynchronous programming.
Module 14 (Optional): Threading and Asynchronous Programming |
75 |
|
|
|
Support for Asynchronous Programming in .NET
Topic Objective
To provide a high level overview of the .NET Framework support for asynchronous programming.
Lead-in
In addition to support for asynchronous programming in many areas of .NET, the
.NET Framework offers an asynchronous programming design pattern.
!Supported in Many Areas of .NET
#I/O, sockets, networking, remoting, ASP.NET and Web Services, messaging (MSMQ), delegates
!Offers a design pattern for asynchronous programming
#Consistent and type-safe programming model
#User-created classes should conform to this design pattern
*****************************ILLEGAL FOR NON-TRAINER USE******************************
With asynchronous programming in the .NET Framework, you make a call to a
.NET Framework class method while the program continues execution until a specified callback is made. If no callback is specified, the program continues execution until it encounters blocking, polling, or waiting for the call to complete.
For example, a program can call a method which enumerates a large list, while the main program continues to execute. When the enumeration is complete, a callback is made and the program addresses it.
Many areas of the .NET Framework support asynchronous programming, including:
!File IO, Stream IO, Socket IO
!Networking: HTTP, TCP
!Remoting channels (HTTP, TCP) and proxies
!XML Web services created by using ASP.NET
!ASP.NET Web Forms
!Messaging message queues over MSMQ
!Asynchronous delegates
The .NET Framework provides a design pattern that makes asynchronous calls uniform across the different parts of the framework. This pattern is very useful for making complex calls that take a considerable amount of time to complete. User-created classes that support asynchronous calls should conform to this design pattern.
76 |
Module 14 (Optional): Threading and Asynchronous Programming |
Design Pattern for Asynchronous Programming
Topic Objective
To provide details of the asynchronous design pattern.
Lead-in
One of the innovations that is provided by the asynchronous design pattern is that the caller can decide whether a particular call should be asynchronous.
!Caller decides whether to make a synchronous or asynchronous call
#Server may explicitly implement asynchronous methods, or client can use delegate object’s asynchronous support
!Caller does asynchronous operation in two parts
#Call begin method to supply parameters and start operation
-an object implementing IAsyncResult is returned
#When operation is done, call end method to obtain the results
!Caller has several options to know when operation is done
#Callback method - if specified in the begin method call, callback is invoked
#Poll – check IAsyncResult.IsCompleted property
#Call end method – if called before operation is done, automatically waits
#Wait – wait on IAsyncResult.WaitHandle property, can use timeouts
*****************************ILLEGAL FOR NON-TRAINER USE******************************
One of the innovations that is provided by the asynchronous design pattern is that the caller can decide whether a particular call should be asynchronous. You do not need to do additional programming for the called object for it to support asynchronous client calls. The client can make an asynchronous call on another object whose class does not explicitly support such calls by instantiating a delegate object that refers to the object’s method.
The runtime and language compilers encapsulate methods that provide asynchronous operation into delegate classes. The called object can choose to explicitly support asynchronous behavior; either because it can implement asynchronous behavior more efficiently than by using a general architecture, or because the called object is designed to support only asynchronous behavior by its callers. The level of asynchronous support of the called object is up to the object’s author.
However, if an object is to explicitly support asynchronous methods, you should follow the asynchronous design pattern for exposing these methods.
Details of the asynchronous design pattern
In the .NET Framework asynchronous design pattern, the asynchronous operation is split into two logical parts: the part where the client calls a begin operation method and provides input to start the asynchronous operation, and the part where the results of the asynchronous operation are obtained by the client through a call to an end operation method.
Module 14 (Optional): Threading and Asynchronous Programming |
77 |
|
|
|
Beginning the asynchronous operation
In the first part of an asynchronous call, the caller upon invoking the begin operation method can also supply an optional AsyncCallback delegate, in addition to providing the input needed for the operation. This delegate refers to the method to be called when the asynchronous operation is completed. The begin method synchronously returns an object that implements the IAsyncResult interface. The caller can use the methods of this interface to determine the status of the asynchronous operation. The server typically maintains any state that is associated with an asynchronous operation in this waitable object.
The IAsyncResult interface specifies the properties that are listed in the following table.
IAsyncResult interface property |
Description |
AsyncState |
AsyncState returns the object that was provided as |
|
the last parameter, as part of the begin operation |
|
method call. |
AsyncWaitHandle |
The AsyncWaitHandle property returns the |
|
WaitHandle that is set after the server has |
|
completed processing of the call. |
CompletedSynchronously |
The CompletedSynchronously property is set to |
|
true if the begin operation call completes |
|
synchronously. |
IsCompleted |
The IsCompleted property is set to true after the |
|
server completes processing of the call. |
Obtaining the results of the asynchronous operation
In the second part of an asynchronous call, the caller obtains the results of the operation in one of the four following ways:
!Callback Method
If the caller supplied the optional AsyncCallback delegate, the callback method referred to by this delegate will be called when the operation completes.
!Polling
The caller can poll the returned IAsyncResult interface’s IsCompleted property to determine if the call has completed.
!End Operation Method
The caller can attempt to complete the operation by calling the end operation method, thereby blocking until the operation completes.
!WaitHandle, End Operation Method
The caller can wait on the IAsyncResult interface’s WaitHandle property. One difference between this and the previous option is that the client can use time outs to wake up periodically. Another difference is that the caller can choose to wait for multiple events to occur by calling the WaitAll method in the Thread.WaitHandle class and specifying an array of events, see the topic, Using the WaitHandle class to wait for events in this module.
78 |
Module 14 (Optional): Threading and Asynchronous Programming |
Note Cancel is not provided on IAsyncResult, because in many implementations, there is no guarantee that an asynchronous operation will be canceled.
Exceptions
If the begin operation method throws an exception, the caller can assume that an asynchronous operation was not started and that the callback delegate will not be called.
After an asynchronous operation starts, the client is notified of any exceptions that are raised by the server when the client calls the end operation method.
Module 14 (Optional): Threading and Asynchronous Programming |
79 |
|
|
|
Asynchronous File Stream Read Example
Topic Objective
To show the first part of the Asynchronous File Stream Read example by explaining how to do an asynchronous read using a callback.
Lead-in
Let’s first look at how to do an asynchronous read by using a callback.
! Asynchronous read with callback
# Create callback method delegate
AsyncCallback myCallback = new
AsyncCallback myCallback = new
AsyncCallback(this.OnReadDone);
AsyncCallback(this.OnReadDone);
# Begin the operation
IAsyncResult ar = aStream.BeginRead(buffer,0, IAsyncResult ar = aStream.BeginRead(buffer,0,
buffer.Length, myCallback,(object)myState); buffer.Length, myCallback,(object)myState);
# In the callback method, complete the operations
int byteCount = aStream.EndRead(ar); //data in buffer int byteCount = aStream.EndRead(ar); //data in buffer
*****************************ILLEGAL FOR NON-TRAINER USE******************************
The examples in this topic show how to implement a client that uses the System.IO.Stream class’s methods to read a sequence of bytes from a file. The System.IO.Stream class’s synchronous read method is named Read and the asynchronous methods are named BeginRead and EndRead.
For the complete running code of these examples, see <install folder>\
Democode\Mod14\Demo14.6.
The following code uses a byte array named buffer to store the bytes returned from the read operation:
byte[] buffer = new byte [512]; string filename = "test.txt"
Stream aStream = File.OpenRead(filename);
The following code uses a synchronized call to read data from the file:
int byteCount = aStream.Read(buffer, 0, buffer.Length); aStream.Close();
Details of the asynchronous read operation
The asynchronous operation consists of two logical parts: the part that takes input from the client and calls the asynchronous operation, and the part that supplies results of the asynchronous operation to the client.
80 |
Module 14 (Optional): Threading and Asynchronous Programming |
Asynchronous Read With Callback
In this example the callback method is an instance method named OnReadDone, which returns void and takes a single parameter of type IAsyncResult. The System namespace defines a delegate class AsyncCallback that matches the signature for the instance method so that there is no need to declare a new delegate type.
You create the callback delegate object as follows:
AsyncCallback myCallback = new AsyncCallback(this.OnReadDone);
If the caller may issue multiple asynchronous calls, the caller must be able to correlate each of the results to the original call. You can use the state parameter of the method that makes the asynchronous call to store this information.
In this example, you store the name of the file being read in an instance of
MyState:
class MyState
{
public string filename;
public MyState(string filename) { this.filename = filename;
}
}
// ...
MyState myState = new MyState(filename);
You can now make the asynchronous call as follows:
IAsyncResult ar = aStream.BeginRead(
buffer, 0, buffer.Length, myCallback, (object)myState); // continue to execute
The BeginRead method returns and the thread can continue to execute while the read operation proceeds. When the read operation completes, the OnReadDone method is called, possibly on a separate thread. This method performs the second part of the asynchronous operation, obtaining the results of the operation as follows:
int byteCount = aStream.EndRead(ar); // data now in buffer Console.WriteLine("Filename read: {0},
((MyState)(ar.AsyncState)).filename); aStream.Close();
The next topic, Asynchronous File Stream Read Example (Continued), completes the example, by showing how to do an asynchronous read with polling.
Module 14 (Optional): Threading and Asynchronous Programming |
81 |
|
|
|
Asynchronous File Stream Read Example (continued)
Topic Objective
To continue the Asynchronous File Stream Read example by explaining how to do an asynchronous read with polling.
Lead-in
Now let’s see how to do an asynchronous read with polling.
!Asynchonous read with polling
#Begin the operation
IAsyncResult ar = aStream.BeginRead(buffer,0, IAsyncResult ar = aStream.BeginRead(buffer,0,
buffer.Length, null,(object)myState); buffer.Length, null,(object)myState);
# Poll and complete
while (!ar.IsCompleted){ // do whatever while (!ar.IsCompleted){ // do whatever
}}
int byteCount = aStream.EndRead(ar); // data in buffer int byteCount = aStream.EndRead(ar); // data in buffer
*****************************ILLEGAL FOR NON-TRAINER USE******************************
The preceding topic showed how to complete an asynchronous read operation by using a callback delegate. In this topic, you will see how to obtain results of the asynchronous read with polling.
Asynchronous Read with Polling
To handle the second part of the asynchronous operation by polling for completion rather than using a callback method, you make the initial asynchronous call by supplying a null value for the callback method.
IAsyncResult ar = aStream.BeginRead(
buffer, 0, buffer.Length,null, (object)myState);
The BeginRead method returns and the thread can continue to execute while the read operation proceeds. In this case, the thread periodically polls the IsCompleted property of the IAsyncResult to determine when the read operation is complete.
while (!ar.IsCompleted)
{
// do whatever
}
int byteCount = aStream.EndRead(ar); // data now in buffer Console.WriteLine("Filename read: {0},
((MyState)(ar.AsyncState)).filename); aStream.Close();
82 |
Module 14 (Optional): Threading and Asynchronous Programming |
Demonstration: Asynchronous File Stream Read
Topic Objective
To demonstrate how to use synchronous and asynchronous read methods on a file stream.
Lead-in
In this demonstration, you will see how to use synchronous and asynchronous read methods on a file stream.
*****************************ILLEGAL FOR NON-TRAINER USE******************************
This demonstration shows how to use synchronous and asynchronous read methods on a file stream. For the asynchronous case, the four different ways to complete the operation are shown: callback, poll, end method call, and wait with timeout.
Notice that in the asynchronous case that uses a callback method, the callback method may be executed on a different thread than the main code.
The code for this demonstration is located in <install folder>\Democode\
Mod14\Demo14.6.