Relations Async, Await and the ConfigureAwait

[Transfer] https://mp.weixin.qq.com/s/h10V-FshGoaQUWFPfy-azg

 

In the .NET Framework 4.5, async / await keywords have been added to this version, simplifying multithreaded operations to make asynchronous programming easier to use. In order to maximize the use of resources not suspend UI, you should try to use asynchronous programming as possible. Although the async / await make asynchronous programming easier, but there are some you may not know the details and where noted
 

New Keyword

Microsoft added the async and await keywords in the .NET framework. However, using them, the return type should be Task type. (We will discuss the exceptions later) To use the await keyword, you must use async in the method definition. If you put in the async method definition, you should have at least one keyword await somewhere in the body of the method, if you are missing him, you will usually receive a warning of Visual Studio.
The following is an example of code:

1 public async Task ExecuteAsync(UpdateCarCommand request, CancellationToken token = default)
2         {
3             using (var context = _contextFactory.Create())
4             {
5                 var entity = context.Cars.FirstOrDefault(a => a.Id == request.Id);
6                 // Mapping logic
7                 await context.SaveChangesAsync(token);
8             }
9         }

 

If you want to asynchronous method returns some content, you can use the Task generic. Declared like this (if you want to return the number of rows affected)

1 public async Task<int> ExecuteAsync(UpdateCarCommand request, CancellationToken token = default)
2         {
3             using (var context = _contextFactory.Create())
4             {
5                 var entity = context.Cars.FirstOrDefault(a => a.Id == request.Id);
6                 // Mapping logic
7                 return await context.SaveChangesAsync(token);
8             }
9         }

 

async.await brought us what?

Although this may seem simple, but what does it help? Finally, all of these operations are waiting for the database to return the results (in this case) so that other requests using the current thread. When you request it may take some time to run to the external source database, disk, internet, etc. We can use async / wait to make another request to use this thread. In this way, we would not have free "worker" (thread) there, waiting for the completion of other tasks. It's like going fast food restaurants, like after you order a meal, other people will not point anything until you finish so far. Use async / await, others can under their orders after you point a meal, and can handle multiple orders simultaneously.

 

What it can not do?

One thing to note here is async / await not parallel / multi-core programming. When you use async / await, deal only with the thread and let other threads use it. What the code is similar to "synchronize" because you can continue your code after await with this method. Therefore, if there are four await in a method, you must wait until the next method call after each method are completed. Therefore, you must use the task library or any method you like to generate a new thread, so that they run in parallel. However, you can also let each thread using async / wait, so they do not clog up resources!

 

ConfigureAwait (false) What can we do?

By default, when you use the async / await, it will continue to run (state machine) on the original thread start request. However, if the current long-running another process has taken over this thread, then you have to wait for it to finish. To avoid this problem, you can use the methods and parameters ConfigureAwait of false. When you use this method, when it will tell Task it can restore itself continues to run on any available thread, rather than waiting for the original thread that created it. This will speed up response time and avoid many deadlocks.

However, there is a little loss. When you continue on another thread, thread synchronization context will be lost, because the state machine changes. Here is your biggest loss attributable to lose the thread of Culture and Language, which includes the area as well as information from the original HttpContext.Current like a thread when the national language, so if you do not need this multi-language or HttpContext operate any type of setting, you can call this method safely. Note: If you need language / culture, you can always store the current value before the relevant state await, and then reapply it after await new thread.

 
The following is an example ConfigureAwait (false) is:

1  public async Task<int> ExecuteAsync(UpdateCarCommand request, CancellationToken token = default)
2         {
3             using (var context = _contextFactory.Create())
4             {
5                 var entity = context.Cars.FirstOrDefault(a => a.Id == request.Id);
6                 // Mapping logic
7                 return await context.SaveChangesAsync(token).CongifureAwait(false);
8             }
9         }

 

Precautions

Synchronization -> asynchronous

If you are using async / await, to note a few things. The biggest problem you may encounter is handling asynchronous method request synchronization method. If you develop a new project, it can usually be async / await method from top to bottom throughout the chain, without doing too much work. However, if you are in the outer layer are synchronized, and asynchronous library must be called, then there will be some risks of the operation. If not careful, it will lead to large quantities of deadlock

if synchronous method call asynchronous method, you must use ConfigureAwait (false). If you do not, it will immediately fall into the trap of deadlock. What happens is async method calls the main thread, the thread will eventually be blocked until the completion of the async method. However, once the asynchronous method is complete, it must wait for the original caller to complete before continuing. They are waiting for the other to complete, and never will. By using configurewait (false) in the call, async methods will be able to complete another thread on their own operations, without regard to the location of their state machines and informs that it has completed the original thread. This call best practices carried out as follows:

1 [HttpPut]
2 public IActionResult Put([FromBody]UpdateCommand command) =>
3     _responseMediator.ExecuteAsync(command).ConfigureAwait(false).GetAwaiter().GetResult();

 

.NET Standard与ConfigureAwait(false)

In .NETCore, Microsoft removed the cause we all need ConfigureAwait anywhere (false) of SynchronizationContext. Thus, ASP.NETCore application does not require any technically ConfigureAwait (false) logic, since it is superfluous. However, if there is a development in the use of .NETStandard library, it is strongly recommended that still use .ConfigureAwait (false). In .NETCore, which is automatically invalid. But if .NETFramework people end up using this library and synchronize call it, they will encounter a bunch of trouble. But as .NET5 by .NETCore built, so the future mostly .NetCore call .Netstadard, if you are not prepared to let .NetFramework call your standard library, no need to be compatible.
 

ConfigureAwait (false) throughout

If there is a synchronous call may call your asynchronous method, then the entire call stack for each asynchronous call, you will be forced to set up. ConfigureAwait (false)! Failure to do so will lead to another deadlock. The problem here is that each async / await call for its current methods are local. Thus, each different async / await the call chain may eventually restored on a different thread. If a synchronous call all the way down, we encountered without configurewait (false) task, the task will try to top the original thread wait for the completion before continuing. While this will eventually make you feel tired heart, because all calls to check whether to set this property.
 

Spending

Although the async / await can greatly increase the number of requests processed the application once, but use it at a price. Each async / await the final call will create a small state machine to keep track of all the information. Although this overhead is small, but if abused async / await, will result in slower. Only when a thread has to wait for the result, we should wait for it.
 

Async Void

Although almost all of the async / await method should return some type of Task, but there is one exception to this rule: In some cases, you can use the async void. However, when you use it, the caller will not actually wait after the task is completed to recover himself. It is actually a thing that is made a forgettable. There are two cases you want to use it. 
 
The first case is an event handler, such as WPF or WinForms click of a button. By default, define event handlers must be void. If you take a job in there, the program will not compile, and returns the event something would feel very strange. If the button calls an asynchronous async, you must perform async void in order to make it work. Fortunately, this is what we want, because such use does not block the UI. 
 
The second request is something you do not mind waiting for the results obtained. The most common example is sending log messages, but do not want to wait for it to complete or do not care if it is completed. 
 
However, for both cases, there are some drawbacks. First, call the method does not try / catch any unusual call. It will eventually enter the AppDomain UnhandledException event. However, if a try catch into async void in the actual process, it is possible to effectively prevent this from happening. Another problem is that the caller will never know when it's over, because it does not return anything. So, if you care about when to complete a Task, you actually need to return a Task.
 

 

Discussion .NetCore asynchronous Notes

In .NetCore been excluded SynchronizationContext, removed his main reason is mainly performance and further streamline operations

In .NetCore we do not continue to care for asynchronous synchronization mixed case, if there is no where to set the deadlock problem ConfigureAwait (false) will result, because in .netcore the async / await may be executed on any thread, and can run in parallel!

The following code as an example:

 1 private HttpClient _client = new HttpClient();
 2 
 3 async Task<List<string>> GetBothAsync(string url1, string url2)
 4 {
 5     var result = new List<string>();
 6     var task1 = GetOneAsync(result, url1);
 7     var task2 = GetOneAsync(result, url2);
 8     await Task.WhenAll(task1, task2);
 9     return result;
10 }
11 
12 async Task GetOneAsync(List<string> result, string url)
13 {
14     var data = await _client.GetStringAsync(url);
15     result.Add(data);
16 }

 

Download it two strings and place them into a List. This code works correctly in older ASP.NET (.NetFramework), since the requests are provided at the await, request context allows only one connection.

Which result.Add(data)can only be executed by a thread, as it performs in the request context.

However, the same code is unsafe in ASP.NET Core; specifically, the result.Add(data)row by the two threads may be executed simultaneously, without shared protection List<string>.

Therefore .Netcore pay special attention to problems caused by asynchronous code implementation in parallel

 

Reference: https: //stackoverflow.com/questions/31186354/async-await-where-is-continuation-of-awaitable-part-of-method-performed

Guess you like

Origin www.cnblogs.com/bangle/p/11324991.html