Event-based Asynchronous Pattern Overview基于事件的异步模式概览


Applications that perform many tasks simultaneously, yet remain responsive to user interaction, often require a design that uses multiple threads.
The System.Threading namespace provides all the tools necessary to create high-performance multithreaded applications,
but using these tools effectively requires significant experience with multithreaded software engineering.
For relatively simple multithreaded applications, the BackgroundWorker component provides a straightforward solution.
For more sophisticated asynchronous applications, consider implementing a class that adheres to the Event-based Asynchronous Pattern.

The Event-based Asynchronous Pattern makes available the advantages of multithreaded applications while hiding many of the complex issues inherent in multithreaded design. Using a class that supports this pattern can allow you to:
1.Perform time-consuming tasks, such as downloads and database operations, "in the background," without interrupting your application.
2.Execute multiple operations simultaneously, receiving notifications when each completes.
3.Wait for resources to become available without stopping ("hanging") your application.
4.Communicate with pending asynchronous operations using the familiar events-and-delegates model.


A class that supports the Event-based Asynchronous Pattern will have one or more methods named MethodNameAsync.
These methods may mirror synchronous versions, which perform the same operation on the current thread.
The class may also have a MethodNameCompleted event and it may have a MethodNameAsyncCancel (or simply CancelAsync) method.


PictureBox is a typical component that supports the Event-based Asynchronous Pattern.
You can download an image synchronously by calling its Load method, but if the image is large, or if the network connection is slow, your application will stop ("hang") until the download operation is completed and the call to Load returns.


If you want your application to keep running while the image is loading, you can call the LoadAsync method and handle the LoadCompleted event, just as you would handle any other event.
When you call the LoadAsync method, your application will continue to run while the download proceeds on a separate thread ("in the background").
Your event handler will be called when the image-loading operation is complete, and your event handler can examine the AsyncCompletedEventArgs parameter to determine if the download completed successfully.


The Event-based Asynchronous Pattern requires that an asynchronous operation can be canceled, and the PictureBox control supports this requirement with its CancelAsync method.
Calling CancelAsync submits a request to stop the pending download, and when the task is canceled, the LoadCompleted event is raised.


It is possible that the download will finish just as the CancelAsync request is made, so Cancelled may not reflect the request to cancel.
This is called a race condition and is a common issue in multithreaded programming.



Characteristics of the Event-based AsyncChronous Pattern基于事件的一步模式的特征
The Event-based Asynchronous Pattern may take several forms, depending on the complexity of the operations supported by a particular class.
The simplest classes may have a single MethodNameAsync method and a corresponding MethodNameCompleted event.
More complex classes may have several MethodNameAsync methods, each with a corresponding MethodNameCompleted event, as well as synchronous versions of these methods.
Classes can optionally support cancellation, progress reporting, and incremental results for each asynchronous method.

An asynchronous method may also support multiple pending calls (multiple concurrent invocations), allowing your code to call it any number of times before it completes other pending operations.
Correctly handling this situation may require your application to track the completion of each operation.


  • 1.Examples of the Event-based AsyncChronous Pattern基于事件的异步模式的例子

The SoundPlayer and PictureBox components represent simple implementations of the Event-based Asynchronous Pattern.
The WebClient and BackgroundWorker components represent more complex implementations of the Event-based Asynchronous Pattern.
Below is an example class declaration that conforms to the pattern:


public class AsyncExample
        // Synchronous methods.
        public int Method1(string param);
        public void Method2(double param);

        // Asynchronous methods.
        public void Method1Async(string param);
        public void Method1Async(string param, object userState);
        public event Method1CompletedEventHandler Method1Completed;

        public void Method2Async(double param);
        public void Method2Async(double param, object userState);
        public event Method2CompletedEventHandler Method2Completed;

        public void CancelAsync(object userState);

        public bool IsBusy { get; }

        // Class implementation not shown.

 The fictitious AsyncExample class has two methods, both of which support synchronous and asynchronous invocations. 
The synchronous overloads behave like any method call and execute the operation on the calling thread;
if the operation is time-consuming, there may be a noticeable delay before the call returns. 
The asynchronous overloads will start the operation on another thread and then return immediately, allowing the calling thread to continue while the operation executes "in the background."


  • 2.AsyncChronous Method Overloads异步方法的重载

There are potentially two overloads for the asynchronous operations: single-invocation and multiple-invocation.
You can distinguish these two forms by their method signatures: the multiple-invocation form has an extra parameter called userState.
This form makes it possible for your code to call Method1Async(string param, object userState) multiple times without waiting for any pending asynchronous operations to finish.
多次调用的形式确保了如下操作变得可能:让你的代码可以多次调用Method1Async(string param, object userState)方法多次而无需等待挂起的异步操作结束
If, on the other hand, you try to call Method1Async(string param) before a previous invocation has completed, the method raises an InvalidOperationException.
另一方面,如果你在之前的调用还没有结束前,尝试再次调用Method1Async(string param)这个同步方法的时候,这个同步方法将会触发一个无效操作的异常

The userState parameter for the multiple-invocation overloads allows you to distinguish among asynchronous operations.
You provide a unique value (for example, a GUID or hash code) for each call to Method1Async(string param, object userState),
你可以在每一次调用Method1Async(string param, object userState)方法时,使用一个独一无二的值传递给此方法(比如GUID或哈希码)
and when each operation is completed, your event handler can determine which instance of the operation raised the completion event.


  • 3.Tracking Pending Operations追踪挂起的操作

If you use the multiple-invocation overloads, your code will need to keep track of the userState objects (task IDs) for pending tasks.
For each call to Method1Async(string param, object userState), you will typically generate a new, unique userState object and add it to a collection.
每一次调用Method1Async(string param, object userState)方法时,你通常需要生成一个新的,独一无二的userState对象,并将它加入到一个结合中。
When the task corresponding to this userState object raises the completion event, your completion method implementation will examine AsyncCompletedEventArgs.UserState and remove it from your collection.
Used this way, the userState parameter takes the role of a task ID.

You must be careful to provide a unique value for userState in your calls to multiple-invocation overloads.
Non-unique task IDs will cause the asynchronous class throw an ArgumentException.


  • 4.Canceling Pending Operations取消挂起的操作

It is important to be able to cancel asynchronous operations at any time before their completion.
Classes that implement the Event-based Asynchronous Pattern will have a CancelAsync method (if there is only one asynchronous method) or a MethodNameAsyncCancel method (if there are multiple asynchronous methods).

Methods that allow multiple invocations take a userState parameter, which can be used to track the lifetime of each task.
CancelAsync takes a userState parameter, which allows you to cancel particular pending tasks.

Methods that support only a single pending operation at a time, like Method1Async(string param), are not cancelable.
一次仅支持一个单独的挂起操作方法,就像Method1Async(string param)一样,是不可以取消的


  • 5.Receiving Progress Updates and Incremental Results接收进度更新以及增量结果

A class that adheres to the Event-based Asynchronous Pattern may optionally provide an event for tracking progress and incremental results.
This will typically be named ProgressChanged or MethodNameProgressChanged, and its corresponding event handler will take a ProgressChangedEventArgs parameter.

The event handler for the ProgressChangedevent can examine the ProgressChangedEventArgs.ProgressPercentage property to determine what percentage of an asynchronous task has been completed.
This property will range from 0 to 100, and it can be used to update the Value property of a ProgressBar.
If multiple asynchronous operations are pending, you can use the ProgressChangedEventArgs.UserState property to distinguish which operation is reporting progress.

Some classes may report incremental results as asynchronous operations proceed.
These results will be stored in a class that derives from ProgressChangedEventArgs and they will appear as properties in the derived class.
You can access these results in the event handler for the ProgressChanged event, just as you would access the ProgressPercentage property.
If multiple asynchronous operations are pending, you can use the UserState property to distinguish which operation is reporting incremental results.


posted @ 2015-05-04 21:45  ChuckLu  阅读(582)  评论(0编辑  收藏  举报