从同步操作方法中调用异步方法:Task.Run或ConfigureAwaits(false) [英] Call async method from sync action methods: Task.Run or ConfigureAwaits(false)

查看:289
本文介绍了从同步操作方法中调用异步方法:Task.Run或ConfigureAwaits(false)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在控制器的同步操作方法中,我可以同时使用以下两种方法来防止 Result 调用异步Task的死锁:使用Task上的 ConfigureAwaits(false)或使用 Task.Run 。在这两种情况下,异步方法都将在线程池中的线程上完成。控制器来源:

I can prevent deadlock for Result call for async Task in sync action method of controller using both: ConfigureAwaits(false) on Task or using Task.Run. In both cases async method will be completed on thread from threadpool. Controller source:

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;
        }
    }
}

/中的输出测试/任务运行(最后两个int值是ManagedThreadId和IsThreadPoolThread):

Output from /test/taskrun (two last int values are ManagedThreadId and IsThreadPoolThread):

OK - 12 - True 
6 - True

/ test / awaitsfalse 的输出相同。有什么区别吗?

Output from /test/awaitsfalse is the same. Is there any difference?

推荐答案

对于异步同步,没有通用的解决方案,但是每个异步模式都不同有不同的问题。有关详细信息,请参阅我的有关Brownfield异步的MSDN文章

There's no universal solution for sync-over-async, only a variety of anti-patterns that each have different problems. For detailed information, see my MSDN article on brownfield async.

ConfigureAwait(false)的问题在于,必须在每个地方 应用它-每一个 await 在调用方法的传递性关闭中。错过一个真的很容易,然后您就会陷入僵局。例如,上次我检查时, HttpClient.GetAsync 缺少一个移动平台版本。即使您(以及您所有的依存关系)完全做到 ,随着时间的推移维护也一样困难。

The problem with ConfigureAwait(false) is that it must be applied everywhere - for every await in the transitive closure of called methods. It's really easy to miss one and then you have a deadlock waiting to happen. For example, last time I checked, HttpClient.GetAsync is missing one for one of their mobile platform builds. And even if you (and all your dependencies) do this perfectly, it's just as hard to maintain over time.

Task.Run 的问题是它在线程池线程上运行代码。 (明显)。这对于可以在线程池线程上运行的代码很好,但是并非所有代码都适用。它的效率也较低,并且(如果使用过度)会导致ASP.NET的可伸缩性问题。

The problem with Task.Run is that it runs the code on a thread pool thread. (Obviously). This is fine for code that can run on a thread pool thread, but that's just not the case for all code. It's also less efficient, and (if overused) can cause scalability problems on ASP.NET.

P.S。如果您坚持要阻止,请使用 GetAwaiter()。GetResult()代替 Result ,因为 Result 将异常包装在 AggregateException 中。

P.S. If you insist on blocking, use GetAwaiter().GetResult() instead of Result, because Result will wrap exceptions in an AggregateException.

这篇关于从同步操作方法中调用异步方法:Task.Run或ConfigureAwaits(false)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆