eme*_*oel 0 c# asp.net asp.net-mvc async-await
当我可以使用.Result以及不能使用.Result时,我仍在努力寻找解决方案。我一直在尝试通过完全“使用异步”来完全避免这种情况。
在我们的ASP.NET Web应用程序(非核心)中进行一些工作时,我遇到了这段代码。现在,该代码可以工作了(已经工作了两年),所以我知道它可以工作,我只是不知道为什么它可以工作。
这是从同步控制器方法触发的。它是一连串的方法调用,经过几层,直到最终完成一些HTTP工作为止。我在这里简化了代码:
// Class1
public byte[] GetDocument1(string url)
{
return class2.GetDocument2(url).Result;
}
// Class2
public Task<byte[]> GetDocument2(string url)
{
return class3.GetDocument3(url)
}
// Class3
public async Task<byte[]> GetDocument3(string url)
{
var client = GetHttpClient(url);
var resp = client.GetAsync(url).Result;
if(resp.StatusCode == HttpStatusCode.OK)
{
using(var httpStream = await resp.Content.ReadAsStreamAsync())
{
// we are also using
await httpStream.ReadAsync(...);
}
}
}
Run Code Online (Sandbox Code Playgroud)
据我所知,这一切开始时,我就在“主ASP同步上下文”上(我从一个控制器开始,最终到达此代码)。我们没有使用任何.ConfigureAwait(false),所以我相信我们总是在回到这种情况。
GetDocument3,为什么不client.GetAsync(url).Result死锁?GetDocument3.Result与await东西混合。总的来说,这是个好主意吗?在这里.Result等待就可以了吗?GetDocument1,为什么不.Result死锁?client.GetAsync(url).Result正在同步阻止。resp.Content.ReadAsStreamAsync()实际上没有做任何等待。在Task已经完成,因为HttpCompletionOption.ResponseContentRead使用在GetAsync,所以整个代码块这里是同步代码假装是异步的。
通常,您永远不应该使用.Result或- .Wait或者Task.Wait*,如果绝对必须使用,请使用GetAwaiter().GetResult(),它不会抛出包裹在AggregateExceptions中的异常,对此您可能没有catch,但即使那样,也应避免瘟疫。您async一路向下使用是正确的。
死锁仅是要返回到原始线程(例如UI或ASP.NET)的上下文中的问题,并且该线程被同步等待阻塞。如果您始终ConfigureAwait(false)在每一个上 使用await,除非您知道您实际上需要在延续上保留上下文(通常仅在顶层UI事件处理程序中保留,因为您需要在UI或ASP.NET的顶层进行更新管理员),那么您应该是安全的。
异步代码内部的同步阻塞也不是一件好事,但不会导致死锁。在要返回到特定线程的上下文中,在同步等待中使用awaitwith ConfigureAwait(true)(默认设置)将导致死锁。
| 归档时间: |
|
| 查看次数: |
196 次 |
| 最近记录: |