从同步操作方法:Task中调用异步方法.运行或configureawait (false)



我可以防止死锁结果调用异步任务同步控制器的动作方法使用: 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中。

最新更新