从同步操作方法:Task中调用异步方法.运行或configureawait (false)
本文关键字:运行 configureawait false 异步方法 调用 操作方法 同步 Task | 更新日期: 2023-09-27 18:15:30
我可以防止死锁结果调用异步任务同步控制器的动作方法使用: configureawait (false) on Task或使用Task. run 。在这两种情况下,异步方法都将在线程池中的线程上完成。控制器来源:
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值是managedthreaddid和IsThreadPoolThread):
OK - 12 - True
6 - True
/test/awaitsfalse的输出与相同。有什么区别吗?
没有通用的同步优于异步的解决方案,只有各种不同的反模式,每个模式都有不同的问题。有关详细信息,请参阅我在MSDN上关于棕地异步的文章。
注:如果坚持阻塞,请使用ConfigureAwait(false)
的问题在于它必须在的任何地方应用 -对于被调用方法的传递闭包中的每个await
。真的很容易错过一个,然后你有一个死锁等待发生。例如,上次我检查的时候,HttpClient.GetAsync
在他们的一个移动平台构建中缺少一个。即使你(和你所有的依赖项)完美地完成了,随着时间的推移,也很难维护。Task.Run
的问题是它在线程池线程上运行代码。(很明显)。对于可以在线程池线程上运行的代码来说,这很好,但并非所有代码都是如此。它的效率也较低,并且(如果过度使用)会导致ASP.NET上的可伸缩性问题。GetAwaiter().GetResult()
而不是Result
,因为Result
会将异常包装在AggregateException
中。