简体   繁体   中英

Difference between calling .Wait() on an async method, and Task.Run().Wait()

I have a server-side click event on a ASP.NET WebForms website. In this event I call a method which in turn calls its async partner method, adding .Wait() on the call.

This method then goes several levels down ( ie , calls another async method, which calls another async method, and so on) and eventually calls an async method on an HttpClient object. At this point the thread seems to disappear down a rabbit hole; the method never calls back.

Now, I know that the async series of calls works as expected because the same code is also called from a Web API controller (the controller method calls the async version of that first method, not the synchronous 'partner' method), which is fully async, and it returns as expected.

So basically I have something like this, which never returns

protected void btn_Click(object sender, EventArgs e)
    > Class1.DoSomething()
        > Class1.DoSomethingAsync.Wait()
            ...
                > await ClassN.Authenticate()
                  {
                    await myHttpClient.PostAsync()  // never returns
                  }

I did try using .ConfigureAwait(false) on that first async method but without any success.

I also have this, which does return

Task<IHttpActionResult> MyWebApiMethod()
    > await Class1.DoSomethingAsync()
        ...
            > await ClassN.Authenticate()
              {
                await myHttpClient.PostAsync()  // does return
              }

I've found that I can make the first version work if I change it to the following:

protected void btn_Click(object sender, EventArgs e)
    > Class1.DoSomething()
        > Task.Run(async () => await Class1.DoSomethingAsync()).Wait()
            ...
                > await ClassN.Authenticate()
                  {
                    await myHttpClient.PostAsync()
                  }

But I don't know why.

Can anyone explain the difference between calling

Class1.DoSomethingAsync.Wait()

and calling

Task.Run(async () => await Class1.DoSomethingAsync()).Wait()

I explain this behavior in my blog post Don't Block on Asynchronous Code and my MSDN article on asynchronous best practices .

the thread seems to disappear down a rabbit hole; the method never calls back.

This happens because one of the await s is attempting to resume on the ASP.NET context, but the request thread (using that ASP.NET context) is blocked waiting for the task to complete. This is what causes your deadlock.

I did try using .ConfigureAwait(false) on that first async method but without any success.

In order to avoid this deadlock using ConfigureAwait(false) , it must be applied to every await in every method called. So DoSomethingAsync must use it for every await , every method that DoSomethingAsync calls must use it for every await (eg, Authenticate ), every method that those methods call must use it for every await (eg, PostAsync ), etc. Note that at the end here, you are dependent on library code, and in fact HttpClient has missed a few of these in the past.

I've found that I can make the first version work if I change it [to use Task.Run ].

Yup. Task.Run will execute its delegate on a thread pool thread without any context. So this is why there's no deadlock: none of the await s attempt to resume on the ASP.NET context.

Why don't you use it the correct way. async void btn_Click and await Class1.DoSomethingAsync() ?

Do not use Task.Run with already asynchronous methods, this is waste of threads. Just change signature of button_click eventhandler

And here's the right answer: don't block on asynchronous code. Just use an async void event handler and use await instead.

PS ASP.NET Core no longer has an ASP.NET context, so you can block as much as you want without fear of deadlocks. But you still shouldn't, of course, because it's inefficient.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM