Don & #39; t Block on Async Code, asyncblock

Source: Internet
Author: User
Tags wrappers

Async method deadlock problem Don't Block on Async Code (transfer), asyncblock

Today, when debugging the requet. GetRequestStreamAsync Asynchronous Method, the problem of not returning results may be a deadlock. I saw an article by a foreigner explaining the deadlock problem of the asynchronous method. The Lazy translation directly moved over.

Http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

This is a problem that is brought up repeatedly on the forums and Stack Overflow. I think it's the most-asked question by async newcomers once they 've learned the basics.

UI Example

Consider the example below. A button click will initiate a REST call and display the results in a text box (this sample is for Windows Forms, but the same principles applyAnyUI application ).

// My "library" method.public static async Task<JObject> GetJsonAsync(Uri uri){  using (var client = new HttpClient())  {    var jsonString = await client.GetStringAsync(uri);    return JObject.Parse(jsonString);  }}// My "top-level" method.public void Button1_Click(...){  var jsonTask = GetJsonAsync(...);  textBox1.Text = jsonTask.Result;}

The "GetJson" helper method takes care of making the actual REST call and parsing it as JSON. The button click handler waits for the helper method to complete and then displays its results.

This code will deadlock.

ASP. NET Example

This example is very similar; we have a library method that performs a REST call, only this time it's used in an ASP. NET context (Web API in this case, but the same principles applyAnyASP. NET application ):

// My "library" method.public static async Task<JObject> GetJsonAsync(Uri uri){  using (var client = new HttpClient())  {    var jsonString = await client.GetStringAsync(uri);    return JObject.Parse(jsonString);  }}// My "top-level" method.public class MyController : ApiController{  public string Get()  {    var jsonTask = GetJsonAsync(...);    return jsonTask.Result.ToString();  }}

This code will also deadlock. For the same reason.

What Causes the Deadlock

Here's the situation: remember from my intro post that after you await a Task, when the method continues it will continueIn a context.

In the first case, this context is a UI context (which appliesAnyUI handle T Console applications). In the second case, this context is an ASP. NET request context.

One other important point: an ASP. NET request context is not tied to a specific thread (like the UI context is), but itDoesOnly allow one thread inAt a time. This interesting aspect is not officially specified ented anywhere AFAIK, but it is mentioned in my MSDN article about SynchronizationContext.

So this is what happens, starting with the top-level method (button#click for UI/MyController. Get for ASP. NET ):

For the UI example, the "context" is the UI context; for the ASP. NET example, the "context" is the ASP. NET request context. this type of deadlock can be caused for either "context ".

Preventing the Deadlock

There are two best practices (both covered in my intro post) that avoid this situation:

Consider the first best practice. The new "library" method looks like this:

public static async Task<JObject> GetJsonAsync(Uri uri){  using (var client = new HttpClient())  {    var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);    return JObject.Parse(jsonString);  }}

This changes the continuation behavior of GetJsonAsync so that it doesNotResume on the context. Instead, GetJsonAsync will resume on a thread pool thread. This enables GetJsonAsync to complete the Task it returned without having to re-enter the context.

 

UsingConfigureAwait(false)To avoid deadlocks is a dangerous practice. You wowould have to useConfigureAwait(false)ForEvery awaitIn the transitive closure of all methods called by the blocking code,Including all third-and second-party code. UsingConfigureAwait(false)To avoid deadlock is at best just a hack ).

As the title of this post points out, the better solution is "Don't block on async code ".

Consider the second best practice. The new "top-level" methods look like this:

public async void Button1_Click(...){  var json = await GetJsonAsync(...);  textBox1.Text = json;}public class MyController : ApiController{  public async Task<string> Get()  {    var json = await GetJsonAsync(...);    return json.ToString();  }}

This changes the blocking behavior of the top-level methods so that the context is never actually blocked; all "waits" are "asynchronous waits ".

Note:It is best to apply both best practices. Either one will prevent the deadlock,BothMust be applied to achieve maximum performance and responsiveness.

Resources
  • My introduction to async/await is a good starting point.
  • Stephen Toub's blog post Await, and UI, and deadlocks! Oh, my! Covers this exact type of deadlock (in January of 2011, no less !).
  • If you prefer videos, Stephen Toub demoed this deadlock live (39: 40-42: 50, but the whole presentation is great !). Lucian Wischik also demoed this deadlock using VB ).
  • The Async/Await FAQ goes into detail on exactly when contexts are captured and used for continuations.

This kind of deadlock is always the result of mixing synchronous with asynchronous code. usually this is because people are just trying out async with one small piece of code and use synchronous code everywhere else. unfortunately, partially-asynchronous code is much more complex and tricky than just making everything asynchronous.

If youDoNeed to maintain a partially-asynchronous code base, then be sure to check out two more of Stephen Toub's blog posts: Too Wrappers for Synchronous Methods and Synchronous Wrappers for Asynchronous Methods, as well as my AsyncEx library.

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.