Tài liệu Design and Implementation Guidelines for Web Clients- P2 - Pdf 87

and Asynchronous
Programming in Web Applications
In This Chapter
This chapter describes how to use two closely related mechanisms to enable
you to
design scaleable and responsive presentation layers for ASP.NET Web
applications.
The two mechanisms are:
● Multithreading
● Asynchronous programming
Performance and responsiveness are important factors in the success of your
application.
Users quickly tire of using even the most functional application if it is
unresponsive
or regularly appears to freeze when the user initiates an action. Even
though it may be a back-end process or external service causing these
problems,
it is the user interface where the problems become evident.
Multithreading and asynchronous programming techniques enable you to
overcome
these difficulties. The Microsoft .NET Framework class library makes these
mechanisms
easily accessible, but they are still inherently complex, and you must design
your application with a full understanding of the benefits and consequences
that
these mechanisms bring. In particular, you must keep in mind the following
points
as you decide whether to use one of these threading techniques in your
application:
● More threads does not necessarily mean a faster application. In fact, the
use of

in
your application, including:
● When there is background processing to perform, such as waiting for
authorization
from a credit-card company in an online retailing Web application
● When you have a one-way operation, such as invoking a Web service to
pass data
entered by the user to a back-end system
● When you have discrete work units that can be processed independently,
such as
calling several SQL stored procedures simultaneously to gather information
that
you require to build a Web response page
Used appropriately, additional threads allow you to avoid your user interface
from
becoming unresponsive during long-running and computationally intensive
tasks.
Depending on the nature of your application, the use of additional threads
can
enable the user to continue with other tasks while an existing operation
continues in
the background. For example, an online retailing application can display a
“Credit
Card Authorization In Progress” page in the client’s Web browser while a
background
thread at the Web server performs the authorization task. When the
authorization
task is complete, the background thread can return an appropriate “Success”
or “Failure” page to the client. For an example of how to implement this
scenario,

requires another thread.
Thread pools are a common requirement in the development of scaleable,
highperformance
applications. Because optimized thread pools are notoriously difficult
to implement correctly, the .NET Framework provides a standard
implementation in
the System.Threading.ThreadPool class. The thread pool is created the
first time
you create an instance of the System.Threading.ThreadPool class.
The runtime creates a single thread pool for each run-time process (multiple
application
domains can run in the same runtime process.) By default, this pool contains
a
maximum of 25 worker threads and 25 asynchronous I/O threads per
processor
(these sizes are set by the application hosting the common language
runtime).
Because the maximum number of threads in the pool is constrained, all the
threads
may be busy at some point. To overcome this problem, the thread pool
provides a
queue for tasks awaiting execution. As a thread finishes a task and returns to
the
pool, the pool takes the next work item from the queue and assigns it to the
thread
for execution.
Benefits of Using the Thread Pool
The runtime-managed thread pool is the easiest and most reliable approach
to
implement multithreaded applications. The thread pool offers the following

allocated from the thread pool.
using System.Threading;
public class CreditCardAuthorizationManager
{
private void AuthorizePayment(object o)
{
// Do work here ...
}
public void BeginAuthorizePayment(int amount)
{
ThreadPool.QueueUserWorkItem(new
WaitCallback(AuthorizePayment));
}
}
For a more detailed discussion of the thread pool, see “Programming the
Thread
Pool in the .NET Framework” on MSDN (http://msdn.microsoft.com/library
/default.asp?url=/library/en-us/dndotnet/html/progthrepool.asp).
Limitations of Using the Thread Pool
Unfortunately, the thread pool suffers limitations resulting from its shared
nature
that may prevent its use in some situations. In particular, these limitations
are:
● The .NET Framework also uses the thread pool for asynchronous
processing,
placing additional demands on the limited number of threads available.
● Even though application domains provide robust application isolation
boundaries,
code in one application domain can affect code in other application
domains in the same process if it consumes all the threads in the thread pool.

Synchronizing Threads
If you use multiple threads in your applications, you must address the issue
of
thread synchronization. Consider the situation where you have one thread
iterating
over the contents of a hash table and another thread that tries to add or delete
hash
table items. The thread that is performing the iteration is having the hash
table
changed without its knowledge; this causes the iteration to fail.
The ideal solution to this problem is to avoid shared data. In some situations,
you
can structure your application so that threads do not share data with other
threads.
This is generally possible only when you use threads to execute simple one-
way
tasks that do not have to interact or share results with the main application.
The
thread pool described earlier in this chapter is particularly suited to this
model
of execution.
Synchronizing Threads by Using a Monitor
It is not always feasible to isolate all the data a thread requires. To get thread
synchronization,
you can use a Monitor object to serialize access to shared resources by
multiple threads. In the hash table example cited earlier, the iterating thread
would
obtain a lock on the Hashtable object using the Monitor.Enter method,
signaling to
other threads that it requires exclusive access to the Hashtable. Any other

whose
finally block calls the static (or Shared) System.Monitor.Exit method on
the expression.
This ensures the lock is freed even when an exception is thrown. As a result,
it
is invalid to branch into a lock (or SyncLock) block from outside of the
block.
For more information about the Monitor class, see “Monitor Class” in the
“.NET
Framework Class Library” on MSDN (http://msdn.microsoft.com/library
/default.asp?url=/library/en-
us/cpref/html/frlrfsystemthreadingmonitorclasstopic.asp).
Using Alternative Thread Synchronization Mechanisms
The .NET Framework provides several other mechanisms that enable you to
synchronize
the execution of threads. These mechanisms are all exposed through classes
in the System.Threading namespace. The mechanisms relevant to the
presentation
layer are listed in Table 6.1.
Chapter 6: Multithreading and Asynchronous Programming in Web
Applications 121
Table 6.1: Thread Synchronization Mechanisms
Mechanism Description Links for More Information
ReaderWriterLock Defines a lock that implements
http://msdn.microsoft.com/library
single-writer/multiple-reader /default.asp?url=/library/en-us
semantics; this allows many /cpref/html/frlrfsystemthreading
readers, but only a single writer, readerwriterlockclasstopic.asp
to access a synchronized object.
Used where classes do much

Mutex when the owner releases it.
Principally used to make sure only
a single application instance can
be run at the same time.
122 Design and Implementation Guidelines for Web Clients
With such a rich selection of synchronization mechanisms available to you,
you
must plan your thread synchronization design carefully and consider the
following
points:
● It is a good idea for threads to hold locks for the shortest time possible. If
threads
hold locks for long periods of time, the resulting thread contention can
become a
major bottleneck, negating the benefits of using multiple threads in the first
place.
● Be careful about introducing deadlocks caused by threads waiting for
locks held
by other threads. For example, if one thread holds a lock on object A and
waits
for a lock on object B, while another thread holds a lock on object B, but
waits to
lock object A, both threads end up waiting forever.
● If for some reason an object is never unlocked, all threads waiting for the
lock end
up waiting forever. The lock (C#) and SyncLock (Visual Basic .NET)
statements
make sure that a lock is always released even if an exception occurs. If you
use
Monitor.Enter manually, you must make sure that your code calls

Chapter 6: Multithreading and Asynchronous Programming in Web
Applications 123
Using Asynchronous Operations
Some operations take a long time to complete. These operations generally
fall into
two categories:
● I/O bound operations such as calling SQL Server, calling a Web service,
or calling
a remote object using .NET Framework remoting
● CPU-bound operations such as sorting collections, performing complex
mathematical
calculations, or converting large amounts of data
The use of additional threads to execute long running tasks is a common way
to
maintain responsiveness in your application while the operation executes.
Because
threads are used so frequently to overcome the problem of long running
processes,
the .NET Framework provides a standardized mechanism for the invocation
of
asynchronous operations that saves you from working directly with threads.
Typically, when you invoke a method, your application blocks until the
method
is complete; this is known as synchronous invocation. When you invoke a
method
asynchronously, control returns immediately to your application; your
application
continues to execute while the asynchronous operation executes
independently. Your
application either monitors the asynchronous operation or receives

124 Design and Implementation Guidelines for Web Clients
Figure 6.1
MSIL signatures for the Invoke, BeginInvoke, and EndInvoke methods in a
delegate
The equivalent C# signatures for these methods are as follows.
// Signature of compiler-generated BeginInvoke method
public IAsyncResult BeginInvoke(string creditcardNumber,
DateTime expiryDate,
double amount,
AsyncCallback callback,
object asyncState);
// Signature of compiler-generated EndInvoke method
public int EndInvoke(IAsyncResult ar);
// Signature of compiler-generated Invoke method
public int Invoke(string creditcardNumber,
DateTime expiryDate,
double amount);
The following sections describe the BeginInvoke, EndInvoke, and Invoke
methods,
and clarify their role in the asynchronous execution pattern. For full details
on how
to use the asynchronous execution pattern, see “Including Asynchronous
Calls” in
the “.NET Framework Developer’s Guide” on MSDN
(http://msdn.microsoft.com
/library/default.asp?url=/library/en-
us/cpguide/html/cpconasynchronousprogramming.asp).
Performing Synchronous Execution with the Invoke Method
The Invoke method synchronously executes the method referenced by the
delegate

scheduling of
the thread, nor can you change the thread’s priority.
● The runtime’s thread pool contains 25 threads per processor. If you invoke
asynchronous operations too liberally, you can easily exhaust the pool
causing
the runtime to queue excess asynchronous operations until a thread becomes
available.
● The asynchronous method runs in the context of a different thread to the
calling
code. This causes problems when asynchronous operations try to update
Windows
Forms components.
The signature of the BeginInvoke method includes the same arguments as
those
specified by the delegate signature. It also includes two additional arguments
to
support asynchronous completion:
● callback argument – Specifies an AsyncCallback delegate instance. If
you specify
a non-null value for this argument, the runtime calls the specified callback
method when the asynchronous method completes. If this argument is a null


Nhờ tải bản gốc
Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status