gpt4 book ai didi

c# - 在异步方法上调用 .Wait() 和 Task.Run().Wait() 之间的区别

转载 作者:行者123 更新时间:2023-11-30 19:54:45 38 4
gpt4 key购买 nike

我在 ASP.NET WebForms 网站上有一个服务器端点击事件。在这种情况下,我调用一个方法,该方法又调用其异步合作伙伴方法,在调用中添加 .Wait()

此方法然后向下几个级别(,调用另一个异步方法,调用另一个异步方法,等等)并最终调用 HttpClient 对象上的异步方法。在这一点上,线程似乎消失在一个兔子洞里;该方法永远不会回调。

现在,我知道异步系列调用按预期工作,因为同样的代码也从 Web API Controller 调用( Controller 方法调用第一个方法的异步版本,而不是同步“伙伴”方法),这是完全异步的,并且按预期返回。

所以基本上我有这样的东西,永远不会返回

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

我确实尝试在第一个异步方法上使用 .ConfigureAwait(false) 但没有成功。

我也有这个,它返回

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

我发现如果我将它更改为以下内容,我可以使第一个版本工作:

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

但我不知道为什么。

谁能解释一下调用的区别

Class1.DoSomethingAsync.Wait()

和调用

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

最佳答案

我在我的博文 Don't Block on Asynchronous Code 中解释了这种行为和我关于 asynchronous best practices 的 MSDN 文章.

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

发生这种情况是因为其中一个 await 正试图在 ASP.NET 上下文中恢复,但是请求线程(使用该 ASP.NET 上下文)被阻止等待任务完成。这就是导致僵局的原因。

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

为了使用 ConfigureAwait(false) 避免这种死锁,它必须应用于 every await in every 调用的方法。所以 DoSomethingAsync 必须为每个 await 使用它,DoSomethingAsync 调用的每个方法都必须为每个 await 使用它(例如, Authenticate), 这些方法调用的每个方法都必须为每个 await (例如,PostAsync)等使用它。请注意最后在这里,您依赖于库代码,事实上 HttpClient 过去错过了其中的一些代码。

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

是的。 Task.Run 将在线程池线程上执行它的委托(delegate),没有任何上下文。所以这就是没有死锁的原因:await 都没有尝试在 ASP.NET 上下文中恢复。

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

这是正确的答案:不要阻塞异步代码。只需使用 async void 事件处理程序并改用 await

附言ASP.NET Core 不再有 ASP.NET 上下文,因此您可以随心所欲地阻止,而不必担心死锁。但你仍然不应该,当然,因为它效率低下。

关于c# - 在异步方法上调用 .Wait() 和 Task.Run().Wait() 之间的区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40810144/

38 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com