我可以使用以下两者: ConfigureAwaits(false)或使用 Task.Run阻止结果调用async任务同步操作控制器中的死锁即可。在这两种情况下,异步方法都将在线程池中的线程上完成。控制器来源:
public class TestController : Controller
{
/// <summary>
/// Thread from threadpool will be used to finish async method.
/// </summary>
public string TaskRun()
{
return Task.Run(GetStatus).Result + " <br/> " +
Thread.CurrentThread.ManagedThreadId + " - " +
Thread.CurrentThread.IsThreadPoolThread;
}
/// <summary>
/// After completion it will try to finish async method in original thread used to work for httprequest.
/// </summary>
public string Deadlock()
{
return GetStatus().Result;
}
/// <summary>
/// Thread from threadpool will be used to finish async method.
/// </summary>
public string AwaitsFalse()
{
return GetStatusAwaitsFalse().Result + " <br/> " +
Thread.CurrentThread.ManagedThreadId + " - " +
Thread.CurrentThread.IsThreadPoolThread;
}
public async Task<string> PureAsync()
{
return await GetStatus() + " <br/> " +
Thread.CurrentThread.ManagedThreadId + " - " +
Thread.CurrentThread.IsThreadPoolThread;
}
public static async Task<string> GetStatusAwaitsFalse()
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync("http://www.google.com")
.ConfigureAwait(false);
return response.StatusCode + " - " +
Thread.CurrentThread.ManagedThreadId + " - " +
Thread.CurrentThread.IsThreadPoolThread;
}
}
public static async Task<string> GetStatus()
{
using (var httpClient = new HttpClient())
{
var response = await httpClient.GetAsync("http://www.google.com");
return response.StatusCode + " - " +
Thread.CurrentThread.ManagedThreadId + " - " +
Thread.CurrentThread.IsThreadPoolThread;
}
}
}
/ test / taskrun 的输出(最后两个int值是ManagedThreadId和IsThreadPoolThread):
OK - 12 - True
6 - True
/ test / awaitsfalse 的输出是相同的。有什么不同吗?
答案 0 :(得分:3)
对于异步同步,没有通用的解决方案,只有各种各样的反模式都有不同的问题。有关详细信息,请参阅我的MSDN article on brownfield async。
ConfigureAwait(false)
的问题在于它必须在无处不在 - 对于被调用方法的传递闭包中的每个await
。它真的很容易 错过一个,然后你就会等待发生死锁。例如,我上次检查时,HttpClient.GetAsync
缺少一个移动平台版本。即使您(以及所有依赖项)完成完美,它也会随着时间的推移维护一样难。
Task.Run
的问题在于它在线程池线程上运行代码。 (明显)。这对于可以在线程池线程上运行的代码来说很好,但对于所有代码而言并非如此。它的效率也较低,(如果过度使用)会导致ASP.NET出现可伸缩性问题。
P.S。如果您坚持要阻止,请使用GetAwaiter().GetResult()
代替Result
,因为Result
会将异常包装在AggregateException
中。