In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-08 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
Today, I will talk to you about the definition and implementation principle of asynchronous Action under ASP.NETMVC, which may not be well understood by many people. in order to make you understand better, the editor has summarized the following content for you. I hope you can get something according to this article.
The Controller creation wizard provided by Visual Studio defaults to creating a Controller type that inherits from the abstract class Controller, and such Controller can only define synchronous Action methods. If we need to define asynchronous Action methods, we must inherit the abstract class AsyncController.
Request processing based on thread pool
ASP.NET handles concurrent HTTP requests through the thread pool mechanism. A Web application maintains a thread pool, and when an incoming request for the application is detected, an idle thread is obtained from the pool to process the request. When the processing is complete, the thread is not recycled, but is released back into the pool. The thread pool has the maximum capacity of a thread, and if the created thread reaches this limit and all threads are "busy", new HTTP requests are placed in a request queue waiting for a thread that has completed the request processing task to be released back into the pool.
We call these threads that process HTTP requests worker threads (Worker Thread), and this county pool is naturally called worker thread pool. ASP.NET, a thread pool-based request processing mechanism, has the following two main advantages:
Reuse of worker threads: although the cost of creating threads is not as high as that of process activation, it is not a "overnight" thing. Frequent creation and release of threads can cause great damage to performance. The thread pool mechanism avoids always creating new worker threads to handle every request, and the created worker threads are greatly reused, and finally improve the throughput capacity of the server.
Limit on the number of worker threads: limited resources have an upper limit on the server's ability to process requests, or the number of request concurrency that a server can handle has a critical point beyond which the entire service will crash because it cannot provide sufficient resources. Due to the thread pool mechanism with good control over the number of worker threads, the number of requests processed concurrently by ASP.NET MVC cannot exceed the maximum allowable capacity of the thread pool, thus avoiding the unlimited creation of worker threads in high concurrency, which leads to the crash of the whole server.
If the request processing operation takes a short time, the worker thread can be released into the thread pool in time to process the next request. But for more time-consuming operations, it means that the worker thread will be monopolized by a request for a long time, if such operations are accessed more frequently, in the case of high concurrency, it means that idle worker threads may not be found in the thread pool to process the latest arrival requests in a timely manner.
If we deal with such time-consuming requests asynchronously, the worker thread can let the background thread take over, and it can be released to the thread pool in time for subsequent request processing, thus improving the throughput of the entire server. It is worth mentioning that asynchronous operations are mainly used for CPU O binding operations (such as database access and remote service invocation, etc.), rather than for asynchronous binding operations, because the overall performance improvement of asynchronous operations comes from the fact that CPU can be released to handle another task when the Imax O device is processing another task. If the time-consuming operation mainly depends on the operation of the native CPU, the asynchronous method will affect the overall performance because of thread scheduling and thread context switching.
2. Definition of two asynchronous Action methods.
After understanding the necessity of defining asynchronous Action methods in AsyncController, let's briefly introduce how asynchronous Action methods are defined. In general, asynchronous Action methods can be defined in two ways, one is to define it as two matching methods XxxAsync/XxxCompleted, and the other is to define a method with a return type of Task.
XxxAsync/XxxCompleted
If we use two matching methods XxxAsync/XxxCompleted to define the asynchronous Action, we can implement the asynchronous operation in the XxxAsync method and the rendering of the final content in the XxxCompleted method. XxxCompleted can be seen as a callback to XxxAsync, and the XxxCompleted method is called automatically when the operation defined in the XxxAsync method is completed asynchronously. The way XxxCompleted is defined is similar to the common synchronous Action method.
As a demonstration, I defined an asynchronous operation called Article in the following HomeController to render the content of the article with the specified name. We define the asynchronous reading of the specified article content in the ArticleAsync method, while the content read in the ArticleCompleted method is rendered in the form of ContentResult.
Public class HomeController: AsyncController {public void ArticleAsync (string name) {AsyncManager.OutstandingOperations.Increment (); Task.Factory.StartNew () = > {string path = ControllerContext.HttpContext.Server.MapPath (string.Format (@ "\ articles\ {0} .html", name)); using (StreamReader reader = new StreamReader (path)) {AsyncManager.Parameters ["content"] = reader.ReadToEnd () } AsyncManager.OutstandingOperations.Decrement ();} public ActionResult ArticleCompleted (string content) {return Content (content);}}
For asynchronous Action methods defined in XxxAsync/XxxCompleted form, ASP.NET MVC does not call XxxAsync methods asynchronously, so we need to customize the execution of asynchronous operations in this method. In the ArticleAsync method defined above, we implement asynchronous reading of the content of the article through parallel programming based on Task. When we define asynchronous Action methods in the form of XxxAsync/XxxCompleted, we frequently use the AsyncManager property of Controller, which returns an object of type AsyncManager, which we will discuss separately in the following section.
In the example provided above, we called the Increment and Decrement methods of the OutstandingOperations property of AsyncManager to initiate notification to ASP.NET MVC at the beginning and end of the asynchronous operation. In addition, we also use the dictionary represented by the Parameters attribute of AsyncManager to save the parameters passed to the ArticleCompleted method. The Key (content) of the parameters in the dictionary matches the parameter name of ArticleCompleted, so when calling the method ArticleCompleted, the parameter value specified through the Parameters attribute of AsyncManager will automatically be the corresponding parameter value.
Task return value
If we use the above definition of asynchronous Action, it means that we have to define two methods for an Action. In fact, we can define asynchronous Action through one method, which is to have the Action method return a Task object that represents an asynchronous operation. The asynchronous Action defined above in the form of XxxAsync/XxxCompleted can be defined as follows.
Public class HomeController AsyncController {public Task Article (string name) {return Task.Factory.StartNew (() = > {string path = ControllerContext.HttpContext.Server.MapPath (string.Format (@ "\ articles\ {0} .html", name)); using (StreamReader reader = new StreamReader (path)) {AsyncManager.Parameters ["content"] = reader.ReadToEnd () ) .ContinueWith (task = > {string content = (string) AsyncManager.Parameters ["content"]; return Content (content);});}}
The return type of the asynchronous Action method Article defined above is Task, and we reflect the reading of the asynchronous file contents in the returned Task object. The callback operation for rendering the contents of the file is registered by calling the ContinueWith method of the Task object, which is automatically invoked after the asynchronous operation is completed.
As shown in the code snippet above, we still use the Parameters property of AsyncManager to pass parameters between asynchronous and callback operations. In fact, we can also use the Result property of the Task object to achieve the same function, and the definition of the Article method is also rewritten as follows.
Public class HomeController AsyncController {public Task Article (string name) {return Task.Factory.StartNew (() = > {string path = ControllerContext.HttpContext.Server.MapPath (string.Format (@ "\ articles\ {0} .html", name)); using (StreamReader reader = new StreamReader (path)) {return reader.ReadToEnd () ) .ContinueWith (task = > {return Content ((string) task.Result);});}}
III. AsyncManager
In the definition of asynchronous Action demonstrated above, we have implemented two basic functions through AsyncManager, namely, passing parameters between asynchronous and callback operations and sending notifications to ASP.NET MVC of the start and end of asynchronous operations. Since AsyncManager plays an important role in asynchronous Action scenarios, it is necessary to introduce it separately. Here is the definition of AsyncManager.
Public class AsyncManager {public AsyncManager (); public AsyncManager (SynchronizationContext syncContext); public EventHandler Finished; public virtual void Finish (); public virtual void Sync (Action action); public OperationCounter OutstandingOperations {get;} public IDictionary Parameters {get;} public int Timeout {get; set;} public sealed class OperationCounter {public event EventHandler Completed; public int Increment (); public int Increment (int value); public int Decrement () Public int Decrement (int value); public int Count {get;}}
As the code snippet above shows, AsyncManager has two constructor overloads, and the non-default constructor accepts a SynchronizationContext object that represents the synchronization context as a parameter. If the specified synchronization context object is Null and the current synchronization context (represented by the static property Current of SynchronizationContext) exists, that context is used; otherwise, a new synchronization context is created. This synchronization context is used for the execution of the Sync method, that is, the Action delegate specified in the method will be executed synchronously in that synchronization context.
At the core of AsyncManager is the asynchronous operation counter in progress represented by the property OutstandingOperations, which is an object of type OperationCounter. The operation count is represented by the read-only property Count. When we start and finish the asynchronous operation, we call the Increment and Decrement methods to add and introduce the count operation. Increment and Decrement each have two overloads, which are used as integer parameters value (which can be negative) to indicate an increased or decreased value, and if a no-parameter method is called, it increases or decreases by 1. If we need to perform multiple asynchronous operations at the same time, we can manipulate the counter in the following way.
AsyncManager.OutstandingOperations.Increment (3); Task.Factory.StartNew () = > {/ / Asynchronous Operation 1 AsyncManager.OutstandingOperations.Decrement ();}); Task.Factory.StartNew () = > {/ / Asynchronous Operation 2 AsyncManager.OutstandingOperations.Decrement ();}); Task.Factory.StartNew () = > {/ / Asynchronous Operation 3 AsyncManager.OutstandingOperations.Decrement ();})
For each change in the count value caused by each Increment and Decrement method call, the OperationCounter object verifies that the current count value is zero, if it indicates that all operations have completed, and if the Completed event is pre-registered, the event will be triggered. When it is worth mentioning, the flag indicating that all operations are completed is that the value of the counter is equal to zero, not less than zero. If we call the Increment and Decrement methods to make the value of the counter a negative number, the registered Completed event will not be triggered.
AsyncManager registers the Completed event of the OperationCounter object represented by the property OutstandingOperations at initialization time, so that its own Finish method is called when the event is triggered. The default implementation of the virtual method Finish in AsyncManager triggers its own Finished event.
As shown in the following code snippet, the Controller class implements the IAsyncManagerContainer interface, which defines a read-only property AsyncManager to provide an AsyncManager object that assists the execution of asynchronous Action, and the AsyncManager object we use in defining asynchronous Action methods is the AsyncManager property integrated from the abstract class Controller.
Public abstract class Controller ControllerBase, IAsyncManagerContainer,... {public AsyncManager AsyncManager {get;}} public interface IAsyncManagerContainer {AsyncManager AsyncManager {get;}}
IV. Execution of Completed method
For an asynchronous Action defined in the form of XxxAsync/XxxCompleted, we say that the callback operation XxxCompleted will be called automatically after the execution of the asynchronous operation defined in the XxxAsync method, so how exactly is the XxxCompleted method executed?
The execution of an asynchronous Action is ultimately done by describing the BeginExecute/EndExecute method of the AsyncActionDescriptor object of the Action. Through the previous introduction of "binding of Model", we know that an asynchronous Action defined by XxxAsync/XxxCompleted is represented by a ReflectedAsyncActionDescriptor object. ReflectedAsyncActionDescriptor registers the Finished event of the AsyncManager of the Controller object when the BeginExecute method is executed, so that the Completed method is executed when the event is triggered.
That is, the trigger of the Finished event for the AsyncManager of the current Controller marks the end of the asynchronous operation, and the matching Completed method is executed. Because the Finish method of AsyncManager actively triggers the event, we can call this method to make the Completed method execute immediately. Because the Finish method is called when the Completed event of the OperationCounter object of AsyncManager is triggered, the Completed method is also automatically executed when the value representing the currently executing asynchronous operation calculator is 00:00.
If we execute three asynchronous operations simultaneously in the XxxAsync method as follows, and call AsyncManager's Finish method after each operation is completed, it means that the first completed asynchronous operation will result in the execution of the XxxCompleted method. In other words, there may be two more asynchronous operations in progress when the XxxCompleted method is executed.
AsyncManager.OutstandingOperations.Increment (3); Task.Factory.StartNew () = > {/ / Asynchronous Operation 1 AsyncManager.Finish ();}); Task.Factory.StartNew () = > {/ / Asynchronous Operation 2 AsyncManager.Finish ();}); Task.Factory.StartNew () = > {/ / Asynchronous Operation 3 AsyncManager.Finish ();})
If the execution of the XxxCompleted method is controlled entirely through the counting mechanism of the asynchronous operation for completion, since the detection of the count and the trigger of the Completed event only occur when the Increment/Decrement method of the OperationCounter is executed, if we do not call these two methods at the beginning and end of the asynchronous operation, will the XxxCompleted execute? Also taking the previously defined asynchronous Action that reads / displays the content of the article as an example, we define the Increment and Decrement method invocation annotation calls to the OutstandingOperations property of AsyncManager in the ArticleAsync method as follows. Will the ArticleCompleted method still work properly?
Public class HomeController AsyncController {public void ArticleAsync (string name) {/ / AsyncManager.OutstandingOperations.Increment (); Task.Factory.StartNew () = > {string path = ControllerContext.HttpContext.Server.MapPath (string.Format (@ "\ articles\ {0} .html", name)); using (StreamReader reader = new StreamReader (path)) {AsyncManager.Parameters ["content"] = reader.ReadToEnd () } / / AsyncManager.OutstandingOperations.Decrement ();});} public ActionResult ArticleCompleted (string content) {return Content (content);}}
In fact, the ArticleCompleted will still be executed, but we cannot ensure that the article content is read properly, because the ArticleCompleted method is executed immediately after the ArticleAsync method is executed. If the article content reading is a relatively time-consuming operation, the content parameter of the ArticleCompleted method that represents the article content has not been initialized at the time of execution. How is the ArticleCompleted implemented in this case?
The reason and simplicity is that the BeginExecute method of ReflectedAsyncActionDescriptor calls the Increment and Decrement methods of the OutstandingOperations property of AsyncManager before and after executing the XxxAsync method. For our example, the Increment method is called to change the value of the calculator to 1 before the ArticleAsync is executed, and then the ArticleAsync is executed, which returns immediately because the method reads the specified file contents asynchronously. Finally, the Decrement method is executed to change the value of the counter to zero. The Completed event of the AsyncManager is triggered and causes the execution of the ArticleCompleted method. At this point, the reading of the contents of the file is in progress, indicating that the content parameters of the content of the article have not been initialized.
An execution mechanism like ReflectedAsyncActionDescriptor also requires us to use AsyncManager, that is, the increment of an unfinished one-step operation counter should not occur in an asynchronous thread, and the definition of the Increment method for the OutstandingOperations property of AsyncManager shown below is incorrect.
Public class HomeController AsyncController {public void XxxAsync (string name) {Task.Factory.StartNew () = > {AsyncManager.OutstandingOperations.Increment (); / /. AsyncManager.OutstandingOperations.Decrement ();});} / other members}
The correct definition method is adopted below:
Public class HomeController AsyncController {public void XxxAsync (string name) {AsyncManager.OutstandingOperations.Increment (); Task.Factory.StartNew () = > {/ /... AsyncManager.OutstandingOperations.Decrement ();});} / other members}
Finally, it is emphasized that whether you explicitly call the Finish method of AsyncManager or call the Increment method of the OutstandingOperations property of AsyncManager so that the value of the counter changes to zero, just allowing the XxxCompleted method to be executed does not really prevent the execution of asynchronous operations.
Fifth, timeout control of asynchronous operation
Although asynchronous operations are suitable for those relatively time-consuming Icano binding operations, it does not mean that there is no limit to the time it takes to perform one-step operations. The asynchronous timeout period is represented by the AsyncManager's integer property Timeout, which represents the total number of milliseconds of the timeout period, with a default value of 45000 (45 seconds). If the Timeout property is set to-1, it means that asynchronous operations are no longer subject to any time limit. For an asynchronous Action defined in the form of XxxAsync/XxxCompleted, a TimeoutException is thrown if the XxxCompleted is not executed within the specified timeout period after the XxxAsync is executed.
If we define an asynchronous Action in the form of a return type of Task, the execution time of the asynchronous operation reflected through the Task is not limited by the Timeout property of AsyncManager. We define an asynchronous Action method called Data to get the data as Model asynchronously and present it through the default View, but there is an infinite loop in the asynchronous operation, and when we access the Data method, the asynchronous operation will be executed indefinitely, and there will be no TimeoutException exception.
Public class HomeController AsyncController {public Task Data () {return Task.Factory.StartNew (() = > {while (true) {} return GetModel ();}) .ContinueWith (task = > {object model = task.Result; return View (task.Result);});} / / other members}
There are two special features in the ASP.NET MVC API for customizing the timeout period for the execution of asynchronous operations. They are AsyncTimeoutAttribute and NoAsyncTimeoutAttribute defined below, both under the namespace System.Web.Mvc.
[AttributeUsage (AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=false)] public class AsyncTimeoutAttribute ActionFilterAttribute {public AsyncTimeoutAttribute (int duration); public override void OnActionExecuting (ActionExecutingContext filterContext); public int Duration {get;}} [AttributeUsage (AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=false)] public sealed class NoAsyncTimeoutAttribute AsyncTimeoutAttribute {/ / Methods public NoAsyncTimeoutAttribute () base (- 1)
From the definition given above, we can see that both features are ActionFilter. The constructor of AsyncTimeoutAttribute takes as its argument an integer representing the timeout in milliseconds, which overrides the OnActionExecuting method to set the specified timeout to the Timeout property of the AsyncManager of the current Controller. NoAsyncTimeoutAttribute, the heir to AsyncTimeoutAttribute, sets the timeout period to-1, meaning it removes the timeout limit.
As can be seen from the AttributeUsageAttribute definitions applied to these two features, they can be applied to both classes and methods, meaning that we can apply them to Controller types or asynchronous Action methods (valid only for XxxAsync methods, not XxxCompleted methods). If we apply them to both the Controller class and the Action method, there is no doubt that there is a higher priority for method-level features.
After reading the above, do you have any further understanding of the definition and implementation principle of asynchronous Action under ASP.NETMVC? If you want to know more knowledge or related content, please follow the industry information channel, thank you for your support.
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.