awj*_*awj 2 c# asp.net asynchronous async-await
我在ASP.NET WebForms网站上有一个服务器端点击事件.在这种情况下,我调用一个方法,该方法又调用其异步伙伴方法,添加.Wait()调用.
然后,此方法向下几级(即,调用另一个异步方法,调用另一个异步方法,依此类推),最终在HttpClient对象上调用异步方法.在这一点上,线程似乎从兔子洞里消失了; 该方法永远不会回电.
现在,我知道异步系列调用按预期工作,因为同样的代码也是从Web API控制器调用的(控制器方法调用第一个方法的异步版本,而不是同步'伙伴'方法),这是完全的异步,它按预期返回.
所以基本上我有这样的东西,永远不会回来
protected void btn_Click(object sender, EventArgs e)
> Class1.DoSomething()
> Class1.DoSomethingAsync.Wait()
...
> await ClassN.Authenticate()
{
await myHttpClient.PostAsync() // never returns
}
Run Code Online (Sandbox Code Playgroud)
我尝试使用.ConfigureAwait(false)第一个异步方法但没有任何成功.
我也有这个,它确实回来了
Task<IHttpActionResult> MyWebApiMethod()
> await Class1.DoSomethingAsync()
...
> await ClassN.Authenticate()
{
await myHttpClient.PostAsync() // does return
}
Run Code Online (Sandbox Code Playgroud)
我发现如果将其更改为以下内容,我可以使第一个版本正常工作:
protected void btn_Click(object sender, EventArgs e)
> Class1.DoSomething()
> Task.Run(async () => await Class1.DoSomethingAsync()).Wait()
...
> await ClassN.Authenticate()
{
await myHttpClient.PostAsync()
}
Run Code Online (Sandbox Code Playgroud)
但我不知道为什么.
任何人都可以解释呼叫之间的区别
Class1.DoSomethingAsync.Wait()
Run Code Online (Sandbox Code Playgroud)
并打电话
Task.Run(async () => await Class1.DoSomethingAsync()).Wait()
Run Code Online (Sandbox Code Playgroud)
我在我的博客文章Do not Block on Asynchronous Code和我的MSDN关于异步最佳实践的文章中解释了这种行为.
线程似乎从兔子洞里消失了; 该方法永远不会回电.
发生这种情况是因为其中一个awaits正在尝试在ASP.NET上下文中继续,但是请求线程(使用该ASP.NET上下文)被阻止等待任务完成.这就是导致僵局的原因.
我确实尝试在第一个异步方法上使用.ConfigureAwait(false)但没有任何成功.
为了避免这种僵局使用ConfigureAwait(false),必须应用到每一个 await在每一个调用的方法.因此DoSomethingAsync必须为每await一个使用它,每个DoSomethingAsync调用的方法必须为每个await(例如Authenticate)使用它,这些方法调用的每个方法必须为每个await(例如PostAsync)等使用它.注意,最后在这里,你依赖于库代码,实际上HttpClient已经错过了过去的一些.
我发现如果我改变它[使用
Task.Run] 我可以使第一个版本工作.
对.Task.Run将在没有任何上下文的线程池线程上执行其委托.所以这就是没有死锁的原因:没有一个await尝试在ASP.NET上下文中恢复.
你为什么不以正确的方式使用它.async void btn_Click并等待Class1.DoSomethingAsync()?
不要将Task.Run与已经异步的方法一起使用,这是浪费线程.只需更改button_click eventhandler的签名即可
这是正确的答案:不要阻止异步代码.只需使用async void事件处理程序并使用await.
PS ASP.NET Core不再具有ASP.NET上下文,因此您可以根据需要阻止,而不必担心死锁.但是你当然不应该这样做,因为它效率低下.
| 归档时间: |
|
| 查看次数: |
4182 次 |
| 最近记录: |