Introduction to Async/Await on ASP. NET, asyncawait

Source: Internet
Author: User
Tags net thread nets cloud hosting

Introduction to Async/Await on ASP. NET, asyncawait

Original article link

Most online resources related to async/await assume that you are developing a client application, but are there any async locations on the server? Yes ". This article provides a conceptual overview of asynchronous requests on ASP. NET and a reference to the best online resource. I am not going to introduce the async or await syntax; because I have already posted an introductory blog article (bit. ly/19 IkogW) and an article on async Best Practices (msdn.microsoft.com/magazine/jj991977. This article focuses on how async works on ASP. NET.

For client applications such as Windows App Store, Windows desktop, and Windows Phone applications, async provides excellent response capabilities. These types of applications use async to ensure the response capability of the user interface. For server applications, the main advantage of async Asynchronization is good scalability. The key to Node. js scalability is its inherent asynchronous nature. Open Web Interface for. NET (OWIN) is completely designed for Asynchronization, and ASP. NET can also be asynchronous. Async: not only applicable to UI applications!

Synchronous and asynchronous request processing

Before going into the asynchronous request processing program, I would like to briefly review the working principles of the synchronous request processing program on ASP. NET. In this example, we assume that requests in the system depend on some external resources, such as databases or Web APIs. When a request is received, ASP. NET assigns a thread pool thread to the request. Because it is synchronously written, the request handler synchronously calls this external resource. This will block the request thread until it returns a call to the external resource.Figure 1It indicates the thread pool with two threads, one of which is blocked and is waiting for external resources.


Figure 1 synchronization waiting for external resources

Finally, a call to the external resource is returned, and the thread is requested to restore and process the request. When the request is completed and the response is ready, the request thread will return to the thread pool.

All these are good, but the number of requests that your ASP. NET Server receives will always exceed the number that its threads can process. At this time, the additional request must wait until the thread is available.Figure 2This indicates that the dual-threaded server still receives three requests.


Figure 2 dual-threaded servers that receive three requests

In this case, the first two requests are allocated to threads in the thread pool. Every request calls external resources and blocks their threads. The third request can be processed only when a thread is available, but the request is already in the system. Its timer is always working, and it is at risk of HTTP Error 503 (Service unavailable.

But consider this: the third request is waiting for the available thread, while the other two threads in the system are actually doing nothing. These threads are blocked and are waiting for external calls to be returned. They do not actually do any work; they are not in the running status, nor occupy any CPU time. These threads are wasted, but there are still requests in need. The following describes how asynchronous requests are handled.

The asynchronous request processing procedure operates in different ways. When a request is received, ASP. NET assigns a thread pool thread to the request. This time, the request handler asynchronously calls this external resource. Before returning a call to an external resource, the request thread has returned this request to the thread pool.Figure 3This indicates that a request has a thread pool of two threads while waiting for external resources asynchronously.


Figure 3 asynchronous waiting for external resources

The important difference is that the request thread has been returned to the thread pool during asynchronous calling. When a thread is in the thread pool, it is no longer associated with the request. When an external resource call is returned, ASP. NET re-allocates a thread in its thread pool to this request. This thread will continue to process the request. When the request is complete, the thread returns to the thread pool again. Note: For synchronous processing programs, the same thread is used for the entire lifecycle of the request. On the contrary, for asynchronous processing programs, different threads can be allocated to the same request (at different times ).

Now, if all three requests come in, the server can easily process them. Every time requests are waiting for asynchronous operation, the threads are released to the thread pool, and they can freely process new and existing requests. Asynchronous requests allow a small number of threads to process a large number of requests. Therefore, the main advantage of asynchronous code on ASP. NET is excellent scalability.

Why not increase the thread pool size?

At this point, I will always be asked: why not increase the thread pool size? There are two answers: asynchronous Code expands deeper and faster than blocking thread pool threads.

The scalability of asynchronous Code exceeds the blocking thread because it uses less memory. In modern operating systems, each thread pool thread has a 1 MB stack, plus a non-Paging Kernel stack. This may sound like a lot, but when there are a lot of threads on your server, you will find that it is not enough. In contrast, the memory overhead of asynchronous operations is much smaller. Therefore, requests that use asynchronous operations face less memory pressure than requests that use blocked threads. Asynchronous Code allows you to use more memory for other tasks (such as cache ).

Asynchronous code is faster than blocking threads because the thread pool injection speed is limited. As of press time, this speed is one thread every two seconds. Limited injection speed is a good thing; it avoids continuous thread construction and destruction. However, consider what will happen when requests flood. The synchronization code is easily paralyzed because requests use up all available threads, and other requests must wait for a new thread injection in the thread pool. On the other hand, asynchronous Code does not need such restrictions; it is "always open". You can say that. Asynchronous code can better respond to sudden fluctuations in Request volume.

Remember that asynchronous Code does not replace the thread pool. The thread pool and asynchronous code should not be the only thread pool or asynchronous code. Asynchronous Code allows your application to make full use of the thread pool. It uses the existing thread pool and increases it to 11.

How does a thread execute asynchronous work?

I have been asked this question all the time. This means that some threads are required to prevent I/O calls to external resources. Therefore, the asynchronous code can only release the request thread at the cost of another thread in the system? No. There is no relationship at all.

To learn why asynchronous requests are extended, I will trace a (simplified) Example of asynchronous I/O calls. Assume that a request needs to be written to the file. The request thread calls the asynchronous write method. WriteAsync is implemented by the Base Class Library (BCL) and uses its asynchronous I/O completion port. Therefore, the WriteAsync call is passed to the OS as an asynchronous file write. Then, the OS communicates with the driver stack and transmits data to be written to the I/O Request Packet (IRP.

Now, the interesting thing is that if the device driver cannot process IRP immediately, it must be processed asynchronously. Therefore, the driver tells the disk to start writing and returns the "suspended" response to the OS. The OS passes the "pending" response to the BCL, and then the BCL returns an incomplete task to the request processing code. The request processing code waits for tasks returned from incomplete tasks such as this method. Finally, the request processing code returns an incomplete task to ASP. NET, And the request thread is released back to the thread pool.

Now, consider the current status of the system. Various I/O structures (such as task instances and IRPs) have been allocated, and they are all suspended/incomplete. However, no thread is blocked by waiting for the write operation to complete. ASP. NET, BCL, OS, and device drivers do not have threads dedicated to asynchronous work.

When the disk completes data writing, it notifies its driver through interruption. The driver notifies the OS that the IRP has been completed and the OS notifies the BCL through the completion port. The thread pool thread responds to the notification by completing the task returned from WriteAsync; this in turn restores the asynchronous request code. In the notification completion phase, some threads are borrowed for a short period of time, but no threads are actually blocked during the write process.

This example is greatly simplified, but the main point is that the real asynchronous work does not require threads. The actual push byte does not require CPU time. There is also a secondary course to learn about. Consider how device drivers can process IRPs immediately or asynchronously in the world of device drivers. Synchronous processing is not an option. At the device driver level, all important I/O operations are asynchronous. Many developers think that "normal APIs" for I/O operations are synchronous, and asynchronous APIs are built on common synchronous APIs as a layer. However, this is exactly the opposite: in fact, normal APIs are asynchronous, and what is implemented using asynchronous I/O is exactly the synchronous API!

Why is there no asynchronous processing program?

If asynchronous request processing is so perfect, why is it still unavailable? In fact, asynchronous code is very suitable for expansion. Therefore, from the beginning of the formation of Microsoft. NET Framework, ASP. NET platform has been supporting asynchronous processing programs and modules. ASP. NET 2.0 introduces Asynchronous web pages. in ASP. net mvc 2, MVC gets an asynchronous controller.

However, recently, asynchronous code coding has always encountered some problems and is difficult to maintain. Many companies decide to develop code synchronously, pay for larger server farms, or more expensive hosting, Which is simpler. Now there is a reversal: in ASP. NET 4.5, asynchronous Code Using async and await is almost as simple as writing Synchronous Code. As large systems are migrated to cloud hosting and require a larger scale, more and more companies are beginning to favor async and await on ASP. NET.

Asynchronous code is not a panacea

Although asynchronous request processing is powerful, it does not solve all problems. There are some common misunderstandings about what async and await can do on ASP. NET.

When some developers understand async and await, they think this is a way for the server code to "give in" to clients (such as browsers. However, async and await on ASP. NET only "Give in" When ASP. NET is running; HTTP remains unchanged, and you still have only one response for each request. If you need SignalR, AJAX, or UpdatePanel before async/await, you still need SignalR, AJAX, or UpdatePanel after async/await.

Asynchronous Request Processing Using async and await can help increase the size of your applications. However, this is an extension on a server; you may still need to plan the extension. If you do need to extend the architecture, you still need to consider stateless idempotent requests and reliable queues. Async/await is helpful: they enable you to make full use of server resources, so you do not need to expand frequently. However, if you do need to scale out, you will need a suitable distributed architecture.

Async and await on ASP. NET are all about I/O. They are ideal for reading and writing files, database records, and REST APIs. However, they cannot execute tasks that occupy a large amount of CPU. You can start some background work by waiting for Task. Run, but this does not make any sense. In fact, heuristic interference with ASP. NET thread pools can damage your scalability. If you want to execute a job that occupies a large amount of CPU on ASP. NET, the best way is to directly execute the job on the request thread. Generally, do not queue jobs to the thread pool on ASP. NET.

Finally, the scalability of the system is considered as a whole. Ten years ago, a common architecture requires an ASP. NET Web Server that can communicate with the back-end SQL Server database. In this simple architecture, database servers are generally the bottleneck of scalability, rather than Web servers. Asynchronous database calls may not be helpful. Of course, you can use them to expand Web servers, but the database server will block the expansion of the entire system.

Rick Anderson gave a case about asynchronous Database Calling in his blog. "Should my Database Calling be asynchronous ?" (Bit. ly/1rw66UB ). The following two arguments are supported: first, asynchronous code is difficult (the developer's time cost is higher than the server that only buys a large one). Second, if the database backend is a bottleneck, it makes no sense to expand the Web server. At the time of writing this article, these two arguments are very reasonable, but the meanings of these two arguments have gradually weakened over time. First, it is easier to write asynchronous Code Using async and await. Second, with the gradual adoption of cloud computing around the world, the website's data backend is gradually extended. The modern backend such as Microsoft Azure SQL database, NoSQL, and other APIs can be further expanded compared with a single SQL Server, thus pushing the bottleneck back to the Web Server. In this case, async/await can bring huge advantages by extending ASP. NET.

Before you start

First, you need to know that only ASP. NET 4.5 supports async and await. There is a NuGet package called Microsoft. Bcl. Async that enables async and await for. NET Framework 4, but does not use it; this will not work properly! The reason is that in order to work better with async and await, ASP. NET itself must change its way of managing asynchronous request processing; the NuGet program package contains all types required by the compiler, but does not fix ASP. NET runtime. No solution; you need ASP. NET 4.5 or later.

Next, you need to know that ASP. NET 4.5 introduces the "quirks mode" on the server ". If you create a new ASP. NET 4.5 project, do not worry. However, to upgrade an existing project to ASP. NET 4.5, all quirks will be opened. We recommend that you edit web. config and set httpRuntime.tar getFramework to 4.5 to disable all of them. If the application using this setting fails (and you do not want to spend time fixing it), at least you can use: useTaskFriendlySynchronizationContext: add the value "true" to the deleetting key to get the async/await job. If you set httpRuntime.tar getFramework to 4.5, the deleteting key is unnecessary. The Web development team has published a blog on bit. ly/1 pbmnzK about the new "quirks mode. Tip: If you see strange behavior or exceptions and your call stack includes LegacyAspNetSynchronizationContext, your application is running in quirks mode. LegacyAspNetSynchronizationContext is incompatible with Asynchronization. On ASP. NET 4.5, you need the regular AspNetSynchronizationContext.

In ASP. NET 4.5, all ASP. NET settings set good default values for asynchronous requests, but there are several other settings that you may want to change. First, IIS settings: consider increasing the queue limit (application pool | Advanced Settings | queue length) of IIS/HTTP. sys from the default 1,000 to 5,000. The other is the. NET runtime setting: ServicePointManager. DefaultConnectionLimit, which defaults to 12 times the number of kernels. DefaultConnectionLimit limits the number of outgoing connections to the same host name.

Message about abort a request

When ASP. NET processes a request synchronously, it has a very simple mechanism to abort the request (for example, if the request exceeds its timeout value): It terminates the working thread of the request. This makes sense, because in the synchronization field, each request uses the same working thread from the beginning to the end. Thread suspension is not perfect for the long-term stability of AppDomain, so ASP. NET recycles your applications on a regular basis by default to keep your applications clean.

For asynchronous requests, ASP. NET does not abort the working thread. Instead, it cancels the CancellationToken request. The asynchronous request processing program should accept and follow the unmark. Most of the newer frameworks (including Web APIs, MVC, and SignalR) will be built and pass you the CancellationToken directly; all you need to do is declare it as a parameter. You can also directly access the ASP. NET tag. For example, HttpRequest. TimedOutToken is a CancellationToken that is canceled when the request times out.

As applications migrate to the cloud, it is more important to abort requests. Cloud-based applications are increasingly dependent on external services that may take up any amount of time. For example, one standard mode is to use exponential rollback to retry external requests. If your application depends on a variety of services like this, it is a good way to apply a timeout limit to your request processing.

Status Quo of Async support

Many libraries have been updated to address async compatibility issues. In version 6, The async support has been added to the Entity Framework (in the EntityFramework NuGet package ). However, when running in asynchronous mode, you must be careful to avoid delayed loading, because delayed loading is always executed in synchronous mode. HttpClient (in Microsoft. Net. Http NuGet package) is a modern HTTP client designed based on the async concept. It is an ideal choice for calling external REST APIs and a modern alternative to HttpWebRequest and WebClient. In version 2.1, the Microsoft Azure Storage client library (in the WindowsAzure. Storage NuGet package) adds asynchronous support.

Newer frameworks (such as Web APIs and SignalR) provide comprehensive support for async and await. Some Web APIs have built the entire pipeline around the support of async: there are not only asynchronous controllers, but also asynchronous filters and processing programs. The Web API and SignalR have an extraordinary asynchronous story: You can "let it go" and then "it will succeed ".

This brings us a sad story: currently, ASP. net mvc only partially supports async and await. Basic Support-asynchronous controller operations and cancellation work normally. The ASP. NET website has a wonderful tutorial on how to use Asynchronous controller operations in ASP. net mvc (bit. ly/1m1LXTx). This is an excellent resource for async entry on MVC. Unfortunately, ASP. net mvc (currently) does not support asynchronous filters (bit. ly/1 oAyHLc) and asynchronous sub-operations (bit. ly/1px47RG ).

ASP. NET Web forms are an older framework, but they also fully support async and await. In addition, tutorials on Asynchronous Web forms on ASP. NET websites are also an excellent resource for getting started (bit. ly/Ydho7W ). With Web forms, you can choose to add asynchronous support. You must set Page. Async to true first, and then you can use PageAsyncTask to register asynchronous work through this Page (or, you can use async void event handler ). PageAsyncTask can also be canceled.

If you have a custom HTTP handler or HTTP module, ASP. NET can now support their asynchronous versions. HTTP processing programs are supported through HttpTaskAsyncHandler (bit. ly/1 nWpWFj), and the HTTP module is supported through EventHandlerTaskAsyncHelper (bit. ly/1m1Sn4O.

As of press time, the ASP. NET team was developing a new project named ASP. NET vNext. In vNext, the entire pipeline is asynchronous by default. Currently, this plan combines MVC and Web APIs into a single framework that fully supports async/await (including asynchronous filters and asynchronous view components. Other asynchronous ready frameworks (such as SignalR) will find a natural home in vNext. Of course, the future is the world of async.

Respect Security Net

ASP. NET 4.5 introduces several new "security nets" to help you capture asynchronous issues in applications. These exist by default and should be retained.

When the synchronous processing program tries to execute asynchronous work, your InvalidOperationException will receive such a message, "Asynchronous Operation cannot begin at this time ". There are two main causes for this exception. First, the Web form Page has an asynchronous event handler, but ignore setting Page. Async to true. Second, the synchronization code calls the async void method. This is another reason to avoid async void.

Another security net applies to asynchronous processing programs: When the asynchronous processing program completes the request, but ASP. when NET detects that the asynchronous work has not been completed, your InvalidOperationException will receive the message "the asynchronous module or processing program has been completed, but the asynchronous operation is still suspended ". This is usually caused by asynchronous code calling the async void method, but it may also be caused by improper use of the event-based asynchronous mode (EAP) component (bit. ly/19 VdUWu ).

You can also use one option to disable the two security nets: HttpContext. AllowAsyncDuringSyncStages (you can also set it in web. config ). We recommend that you set these settings when you see these exceptions on some pages on the Internet. I totally disagree. To be honest, I don't know how this works. Disabling the Security Net is a terrible idea. The only possible reason I can think of is that your code may have undergone some very advanced asynchronous processing (far beyond the scope I have tried ), you are a genius for multi-threaded processing. Therefore, if you have read the entire article and want to "please, I am not a cainiao", you can consider disabling the security net. This is a very dangerous option for others among us. Unless you are fully aware of the consequences, you should not perform this setting.

Start to use

It's finally over! Are you ready to start using async and await? I appreciate your patience.

First, check the "Asynchronous code is not a panacea" section in this article to ensure that async/await is useful for your architecture. Next, update your application to ASP. NET 4.5 and disable the quirks mode. (You can run it only to ensure that no interruption occurs ). Then, you can start real synchronization/waiting for work.

Start with "leaf. Think about how your request is processed and identifies any I/O-based operations, especially network-based operations. Common examples are database queries and commands, and calls to other Web services and APIs. Select one to start and do some research to find the best choice for performing this operation Using async/await .. NET Framework 4.5 has many built-in BCL types which are now ready asynchronously. For example, SmtpClient has the SendMailAsync method. Some types can be replaced asynchronously. For example, HttpWebRequest and Web client can be replaced with HttpClient. If necessary, upgrade your library version. For example, the Entity Framework in EF6 has an asynchronous compatibility method.

However, avoid "false Asynchronization" in the database ". False Asynchronization is like this: a component has an asynchronous ready API, which is only implemented by encapsulating the synchronous API in the thread pool thread. This is counterproductive for implementing scalability on ASP. NET. A typical example of false Asynchronization is Newtonsoft JSON. NET, a library that is excellent in other aspects. It is recommended that you do not call the (false) asynchronous version to execute JSON serialization. You only need to call the synchronous version. A tricky example of false Asynchronization is the BCL file stream. When opening a file stream, it must be opened explicitly for asynchronous access; otherwise, it will use false Asynchronization to synchronously block the thread pool threads in file read and write operations.

After selecting a "leaf", you can start to call the API method in code to make it an Asynchronous Method by waiting to call the asynchronous ready API. If the called API supports CancellationToken, you should use CancellationToken and pass it to the API method.

As long as you mark a method as Asynchronous, you should change its return type: void to "Task", non-void T to "Task <T> ". You will find that all callers of this method need to change to asynchronous so that they can wait for tasks and so on. Additionally, append Async to the name of your method to follow the task-based asynchronous mode Convention (bit. ly/1 uBKGKR ).

Allow async/await mode to extend your call stack to "Trunk. In Trunk, your code is connected to the ASP. NET Framework (MVC, Web forms, Web APIs. Read the tutorials in the "status quo of asynchronous support" section described earlier in this article to integrate your asynchronous code with the Framework.

Find the status of any local thread by the way. Because asynchronous requests may change threads, the local thread status (such as ThreadStaticAttribute, ThreadLocal <T>, thread data slots, and CallContext. GetData/SetData) will be unavailable. If possible, use HttpContext. Items to replace the data, or store the unchangeable data in CallContext. LogicalGetData/LogicalSetData.

Here are some useful tips: You can (temporarily) copy your code to create a vertical partition. With this technology, you do not need to change the synchronous method to asynchronous; you can copy the entire synchronous method and change the copy to asynchronous. Then, you can keep most applications synchronized by creating only one asynchronous vertical slice. This is a great idea if you want to use Asynchronization as a proof of concept to explore or perform load tests only for a portion of your application to experience how to scale your system. You can have a completely asynchronous request (or page), while the rest of the application is synchronized. Of course, you do not want to keep copies of each method. In the end, all I/O binding code will be asynchronous and you can delete synchronous copies.

Summary

I hope this article will help you understand the basic concepts of asynchronous requests on ASP. NET. With async and await, you can make it easier to write Web applications, services, and APIs that maximize the utilization of your server resources. Async is amazing!

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.