In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
How to understand the event-based asynchronous programming mode EMP? aiming at this problem, this article introduces the corresponding analysis and solution in detail, hoping to help more partners who want to solve this problem to find a more simple and feasible method.
The asynchronous programming model (APM) in .NET 1.0 based on the IAsyncResult design pattern, which uses classes from the System.Threading namespace to construct multithreaded applications. However, in order to use these tool classes effectively, you need a wealth of experience in using multithreaded software engineering. For relatively simple multithreaded applications, the BackgroundWorker component provides a simple solution. For more complex asynchronous applications, consider implementing a class that conforms to the event-based asynchronous pattern.
Using classes that support this pattern, you will be able to:
1) perform time-consuming tasks asynchronously.
2) obtain progress reports and incremental results.
3) support the cancellation of time-consuming tasks.
4) get the result value or exception information of the task.
5) more complex: support multiple asynchronous operations, progress reports, incremental results, cancel operations, return result values or exception information at the same time.
Source code download: asynchronous programming: event-based asynchronous model (EAP). Rar
To implement an event-based asynchronous pattern, we must first understand two important helper classes:
AsyncOperationManager and AsyncOperation
The AsyncOperationManager class and the AsyncOperation class are two important helper classes provided by the System.ComponentModel namespace. In the event-based Asynchronous pattern encapsulates standardized asynchronous functionality, it ensures that your asynchronous operations support calls to client event handlers in the appropriate "thread or context" of various application models, including ASP.NET, console applications, and Windows forms applications.
The API of the AsyncOperationManager class and the AsyncOperation class is as follows:
/ / provides concurrency management for classes that support asynchronous method calls. This class cannot be inherited. Public static class AsyncOperationManager {/ / gets or sets the synchronization context for asynchronous operations. Public static SynchronizationContext SynchronizationContext {get; set;} / / returns an AsyncOperation object that can be used to track the duration of a particular asynchronous operation. / / Parameter: userSuppliedState: / / an object that associates a client state (such as task ID) with a specific asynchronous operation. Public static AsyncOperation CreateOperation (object userSuppliedState) {return AsyncOperation.CreateOperation (userSuppliedState,SynchronizationContext);}} / / tracks the lifetime of asynchronous operations. The public sealed class AsyncOperation {/ / constructor private AsyncOperation (object userSuppliedState, SynchronizationContext syncContext); internal static AsyncOperation CreateOperation (object userSuppliedState, SynchronizationContext syncContext); / / gets the SynchronizationContext object passed to the constructor. Public SynchronizationContext SynchronizationContext {get;} / / gets or sets the object used to uniquely identify asynchronous operations. Public object UserSuppliedState {get;} / / invokes delegates in threads or contexts that are appropriate for various application models. Public void Post (SendOrPostCallback d, object arg); / / ends the lifetime of the asynchronous operation. Public void OperationCompleted (); / / effect is the same as calling Post () + OperationCompleted () method to combine public void PostOperationCompleted (SendOrPostCallback d, object arg);}
Let's first analyze these two helper classes:
1. AsyncOperationManager is a static class. Static classes are sealed and therefore cannot be inherited. Inheriting from a static class will error "static class must derive from Object". (common sense, I used to think that sealing class is the sealed keyword.)
2. AsyncOperationManager provides concurrency management for classes that support asynchronous method calls, which run normally in all application modes supported by the .NET Framework.
3. The AsyncOperation instance provides tracking of the lifetime of specific asynchronous tasks. It can be used to process task completion notifications, and to publish progress reports and incremental results without terminating asynchronous operations (which are handled through AsyncOperation's Post () method).
4. The AsyncOperation class has a private constructor and an internal CreateOperation () static method. The AsyncOperation.CreateOperation () static method is called by the AsyncOperationManager class to create the AsyncOperation instance.
5. The AsyncOperation class uses the SynchronizationContext class to invoke client event handlers in the appropriate "thread or context" of various applications.
/ / provides the basic function of propagating synchronization context in various synchronization models. Public class SynchronizationContext {/ / gets the synchronization context of the current thread. Public static SynchronizationContext Current {get;} / / when overridden in a derived class, responds to the notification that the operation has started. Public virtual void OperationStarted (); / / when overridden in a derived class, dispatches asynchronous messages to a synchronous context. Public virtual void Post (SendOrPostCallback d, object state); / / when overridden in a derived class, responds to the notification that the operation has been completed. Public virtual void OperationCompleted ();. }
A) call SynchronizationContext's OperationStarted () in the AsyncOperation constructor
B) call Post () of SynchronizationContext in the Post () method of AsyncOperation
C) call OperationCompleted () of SynchronizationContext in the OperationCompleted () method of AsyncOperation
6. SendOrPostCallback delegated signature:
/ / represents the method to be called when the message is about to be dispatched to the synchronization context. Public delegate void SendOrPostCallback (object state)
Characteristics of event-based Asynchronous pattern
1. Event-based asynchronous patterns can take many forms, depending on the complexity of the operations supported by a particular class:
1) the simplest class may have only one * Async method and a corresponding * Completed event, as well as synchronous versions of these methods.
2) A complex class may have several * Async methods, each with a corresponding * Completed event and a synchronous version of these methods.
3) more complex classes may also support cancellation (CancelAsync () method), progress reports, and incremental results (ReportProgress () method + ProgressChanged event) for each asynchronous method.
4) if your class supports multiple asynchronous methods, each of which returns a different type of data, you should:
A) separate your incremental results report from your progress report.
B) use the appropriate EventArgs to define a separate * ProgressChanged event for each asynchronous method to handle the incremental result data for that method.
5) if the class does not support multiple concurrent calls, consider exposing the IsBusy property.
6) if there are Out and Ref parameters in the synchronous version of the asynchronous operation, they should be used as part of the corresponding * CompletedEventArgs, eg:
Public int MethodName (string arg1, ref string arg2, out string arg3); public void MethodNameAsync (string arg1, string arg2); public class MethodNameCompletedEventArgs: AsyncCompletedEventArgs {public int Result {get;}; public string Arg2 {get;}; public string Arg3 {get;};}
two。 If your component wants to support multiple asynchronous and time-consuming tasks to execute in parallel. So:
1) add an additional userState object parameter to the * Async method (this parameter should always be the last parameter in the * Async method signature) to track the lifetime of each operation.
2) be careful to maintain a collection of userState objects in the asynchronous class you build. Use the lock area to protect this collection because various calls add and remove userState objects from the collection.
3) call AsyncOperationManager.CreateOperation at the beginning of the * Async method and pass in the userState object to create an AsyncOperation object for each asynchronous task. The userState is stored in the UserSuppliedState attribute of AsyncOperation. Use this property to identify canceled operations in the built asynchronous class, and pass the UserState property of the CompletedEventArgs and ProgressChangedEventArgs parameters to identify the specific asynchronous task that currently raises the progress or completes the event.
4) when the task corresponding to this userState object raises a completion event, the asynchronous class you build should remove the AsyncCompletedEventArgs.UserState object from the collection.
3. Note:
1) make sure that the * EventArgs class is specific to * methods. That is, when using the * EventArgs class, do not require developers to cast type values.
2) make sure that the method name Completed event is always raised. This event should be raised on successful completion, exception, or cancellation. Under no circumstances should an application encounter a situation in which the application remains idle while the operation cannot be completed.
3) ensure that any exceptions that occur in an asynchronous operation can be caught and assigned to the Error property.
4) make sure that the * * CompletedEventArgs class exposes its members as read-only properties rather than fields, because fields prevent data binding. Eg:public MyReturnType Result {get;}
5) when building * CompletedEventArgs class attributes, use the this.RaiseExceptionIfNecessary () method to ensure that the attribute values are used correctly. Eg:
Public int MethodName (string arg1, ref string arg2, out string arg3); public void MethodNameAsync (string arg1, string arg2); public class MethodNameCompletedEventArgs: AsyncCompletedEventArgs {public int Result {get;}; public string Arg2 {get;}; public string Arg3 {get;};}
two。 If your component wants to support multiple asynchronous and time-consuming tasks to execute in parallel. So:
1) add an additional userState object parameter to the * Async method (this parameter should always be the last parameter in the * Async method signature) to track the lifetime of each operation.
2) be careful to maintain a collection of userState objects in the asynchronous class you build. Use the lock area to protect this collection because various calls add and remove userState objects from the collection.
3) call AsyncOperationManager.CreateOperation at the beginning of the * Async method and pass in the userState object to create an AsyncOperation object for each asynchronous task. The userState is stored in the UserSuppliedState attribute of AsyncOperation. Use this property to identify canceled operations in the built asynchronous class, and pass the UserState property of the CompletedEventArgs and ProgressChangedEventArgs parameters to identify the specific asynchronous task that currently raises the progress or completes the event.
4) when the task corresponding to this userState object raises a completion event, the asynchronous class you build should remove the AsyncCompletedEventArgs.UserState object from the collection.
3. Note:
1) make sure that the * EventArgs class is specific to * methods. That is, when using the * EventArgs class, do not require developers to cast type values.
2) make sure that the method name Completed event is always raised. This event should be raised on successful completion, exception, or cancellation. Under no circumstances should an application encounter a situation in which the application remains idle while the operation cannot be completed.
3) ensure that any exceptions that occur in an asynchronous operation can be caught and assigned to the Error property.
4) make sure that the * * CompletedEventArgs class exposes its members as read-only properties rather than fields, because fields prevent data binding. Eg:public MyReturnType Result {get;}
5) when building * CompletedEventArgs class attributes, use the this.RaiseExceptionIfNecessary () method to ensure that the attribute values are used correctly. Eg:
Private bool isPrimeValue; public bool IsPrime {get {RaiseExceptionIfNecessary (); return isPrimeValue;}}
Therefore, in the * Completed event handler, you should always check the * CompletedEventArgs.Error and * CompletedEventArgs.Cancelled properties before accessing the RunWorkerCompletedEventArgs.Result property.
BackgroundWorker component
The BackgroundWorker component of the System.ComponentModel namespace provides us with a simple multithreaded application solution that allows you to run time-consuming operations on separate threads without blocking the user interface. Note, however, that it can only run one asynchronous time-consuming operation at a time (determined by the IsBusy attribute) and cannot be marshaled across AppDomain boundaries (multithreaded operations cannot be performed in multiple AppDomain).
1. BackgroundWorker component
Public class BackgroundWorker: Component {public BackgroundWorker (); / / gets a value indicating whether the application has requested to cancel the background operation. Public bool CancellationPending {get;} / / gets a value indicating whether BackgroundWorker is running an asynchronous operation. Public bool IsBusy {get;} / / gets or sets a value indicating whether BackgroundWorker can report progress updates. Public bool WorkerReportsProgress {get; set;} / / gets or sets a value indicating whether BackgroundWorker supports asynchronous cancellation. Occurs when public bool WorkerSupportsCancellation {get; set;} / / calls RunWorkerAsync (). Occurs when public event DoWorkEventHandlerDoWork; / / calls ReportProgress (System.Int32). Public event ProgressChangedEventHandlerProgressChanged; occurs when a background operation is completed, canceled, or an exception is thrown. Public event RunWorkerCompletedEventHandlerRunWorkerCompleted; / / requests to cancel the pending background operation. Public void CancelAsync (); / / raises the ProgressChanged event. PercentProgress: range from 0% to 100% public void ReportProgress (int percentProgress); / / userState: state object passed to RunWorkerAsync (System.Object). Public void ReportProgress (int percentProgress, object userState); / / starts performing background operations. Public void RunWorkerAsync (); / / starts performing background operations. Argument: the DoWorkEventArgs parameter passed to the DoWork event. Public void RunWorkerAsync (object argument);}
two。 The corresponding EventArgs class
/ 1) the System.EventArgs base class / / System.EventArgs is the base class for classes that contain event data. Public class EventArgs {/ / represents an event with no event data. Public static readonly EventArgs Empty; public EventArgs ();} / / 2) the DoWorkEventArgs class / / provides data for cancelable events. Public class CancelEventArgs: EventArgs {public CancelEventArgs (); public CancelEventArgs (bool cancel); / / gets or sets a value indicating whether the event should be canceled. Public bool Cancel {get; set;}} / / provides data for the DoWork event handler. Public class DoWorkEventArgs: CancelEventArgs {public DoWorkEventArgs (object argument); / / gets the value that represents the parameters of the asynchronous operation. Public object Argument {get;} / / gets or sets a value that represents the result of an asynchronous operation. Public object Result {get; set;}} / 3) the ProgressChangedEventArgs class / / provides data for the ProgressChanged event. Public class ProgressChangedEventArgs: EventArgs {public ProgressChangedEventArgs (int progressPercentage, object userState); / / gets the progress percentage of the asynchronous task. Public int ProgressPercentage {get;} / / gets the unique user status. Public object UserState {get;}} / 4) the RunWorkerCompletedEventArgs class / / provides data for the MethodNameCompleted event. Public class AsyncCompletedEventArgs: EventArgs {public AsyncCompletedEventArgs (); public AsyncCompletedEventArgs (Exception error, bool cancelled, object userState); / / gets a value indicating whether the asynchronous operation has been cancelled. Public bool Cancelled {get;} / / gets a value indicating an error that occurred during an asynchronous operation. Public Exception Error {get;} / / gets the unique identifier of the asynchronous task. Public object UserState {get;} / / call this method protected void RaiseExceptionIfNecessary () {if (this.Error! = null) {throw new TargetInvocationException (…) before accessing the properties of AsyncCompletedEventArgs and its derived classes. ;} if (this.Cancelled) {throw new InvalidOperationException (…) ;} public class RunWorkerCompletedEventArgs: AsyncCompletedEventArgs {public RunWorkerCompletedEventArgs (object result, Exception error, bool cancelled); / / gets the value that represents the result of the asynchronous operation. Public object Result {get;} / / gets a value that represents the status of the user. Public object UserState {get;}}
3. BackgroundWorker example
The sample code contains the BackgroundWorker source code and the corresponding usage examples. If you don't paste the code here, it will lead to more space. Let's take a screenshot of an example:
Example analysis:
1) first we register the DoWork (Asynchronous Operation), ProgressChanged (Progress report) and RunWorkCompleted (completion Notification) events for the BackgroundWorker component
2) set the WorkerSupportsCancellation and WorkerReportsProgress properties to true to declare that the component supports canceling operations and progress reporting
3) use RunWorkerAsync () to enable the asynchronous operation, and use the IsBusy attribute to determine whether an asynchronous task is already executing.
4) use the CancelAsync () method to cancel the asynchronous operation, but note:
A) it simply sets the BackgroudWorker.CancellationPending property to true. You need to constantly check the BackgroudWorker.CancellationPending in a specific DoWork event to set the Cancel property of the DoWorkEventArgs.
B) it is possible for the code in the DoWork event handler to finish its work when the cancel request is made, and the polling loop may miss the CancellationPending property set to true. In this case, the Cancelled flag of RunWorkerCompletedEventArgs in the RunWorkerCompleted event handler is not set to true even if a cancel request is issued. This situation is called a contention state. (you can judge by directly monitoring the CancellationPending property of the component.)
5) make sure that no user interface objects are manipulated in the DoWork event handler. Instead, you should communicate with the user interface through ProgressChanged and RunWorkerCompleted events.
Because RunWorkerAsync () is a DoWork event raised through the delegated BeginInvoke (), that is, the thread that executes the DoWork event is no longer the thread that created the control (I introduced several ways to boast thread access to the control in "Asynchronous programming: asynchronous programming Model (APM)"). The ProgressChanged and RunWorkerCompleted events are called in the appropriate "thread or context" through the Post () method of the helper class AsyncOperation.
Customize event-based asynchronous components
We just introduced the BackgroundWorker component, but this component can only turn on one asynchronous operation at a time, so what if we want to support multiple asynchronous operations, progress reports, incremental results, cancels, and return result values or exception information at the same time? Yes, we can define an event-based asynchronous component for ourselves.
I refer directly to an example of an asynchronous component that calculates prime numbers on MSDN, which you can get from the sample code I provided.
Prime number algorithm: Eratosthenes sieve method
Eg: judge whether n is a prime number
1, 1 and 0 are neither prime nor composite numbers
2. Add 2 and 3 to the set of prime numbers, primes; starts with nimble 5, and skips all even numbers through nimble 2.
3. The prime number in the cyclic set primes and takes it as a factor of n, and the divisible number is the composite number.
4. If it is not divisible, continue to follow step 3 until "the square of the factor > n", then you can judge that n is a prime number and add it to the set primes.
Let's take a screenshot of an example:
Example Analysis: (component name: PrimeNumberCalculator)
1. First we register the ProgressChanged (progress report) and CalculatePrimeCompleted (completion notification) events for the PrimeNumberCalculator component
two。 To start an asynchronous task using CalculatePrimeAsync (intnumberToTest, object taskId), notice that we need to pass a unique identification Guid taskId = Guid.NewGuid (); to identify the canceled operation, and to pass the UserState property of the CompletedEventArgs and ProgressChangedEventArgs parameters to identify the specific asynchronous task that currently raises the progress or completion event
3. Canceling the operation CancelAsync (object taskId) only removes the AsyncOperation instance corresponding to the taskId from the internal task set. The time-consuming operation determines whether the taskId is canceled by judging whether it exists in the collection.
This is the answer to the question about how to understand the event-based asynchronous programming mode EMP. I hope the above content can be of some help to you. If you still have a lot of doubts to be solved, you can follow the industry information channel for more related knowledge.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.