加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 从非异步代码调用异步方法

发布时间:2020-12-15 18:04:53 所属栏目:百科 来源:网络整理
导读:我正在更新一个具有.NET 3.5内置API表面的库.因此,所有方法都是同步的.我不能更改API(即将返回值转换为Task),因为这将要求所有的呼叫者都改变.所以我留下了如何以同步的方式最好地调用异步方法.这是在ASP.NET 4,ASP.NET Core和.NET / .NET Core控制台应用程
我正在更新一个具有.NET 3.5内置API表面的库.因此,所有方法都是同步的.我不能更改API(即将返回值转换为Task),因为这将要求所有的呼叫者都改变.所以我留下了如何以同步的方式最好地调用异步方法.这是在ASP.NET 4,ASP.NET Core和.NET / .NET Core控制台应用程序的上下文中.

我可能没有足够清楚 – 情况是我现有的代码不是异步感知的,我想使用新的库,如System.Net.Http和仅支持异步方法的AWS SDK.所以我需要弥合差距,并且能够有可以同步调用的代码,但是可以在其他地方调用异步方法.

我做了很多阅读,有几次这个问题被回答了.

Calling async method from non async method

Synchronously waiting for an async operation,and why does Wait() freeze the program here

Calling an async method from a synchronous method

How would I run an async Task<T> method synchronously?

Calling async method synchronously

How to call asynchronous method from synchronous method in C#?

问题是大部分的答案是不同的!我看到的最常见的方法是使用.Result,但这可能会死锁.我已经尝试过以下所有功能,但是它们仍然可以工作,但是我不确定哪种方法可以避免死锁,具有良好的性能,并且可以很好地运行(在履行任务调度器,任务创建选项等方面) ).有确定的答案吗?什么是最好的方法?

private static T taskSyncRunner<T>(Func<Task<T>> task)
    {
        T result;
        // approach 1
        result = Task.Run(async () => await task()).ConfigureAwait(false).GetAwaiter().GetResult();

        // approach 2
        result = Task.Run(task).ConfigureAwait(false).GetAwaiter().GetResult();

        // approach 3
        result = task().ConfigureAwait(false).GetAwaiter().GetResult();

        // approach 4
        result = Task.Run(task).Result;

        // approach 5
        result = Task.Run(task).GetAwaiter().GetResult();


        // approach 6
        var t = task();
        t.RunSynchronously();
        result = t.Result;

        // approach 7
        var t1 = task();
        Task.WaitAll(t1);
        result = t1.Result;

        // approach 8?

        return result;
    }

解决方法

So I’m left with how to best call async methods in a synchronous way.

首先,这是一件好事.我指出这一点,因为Stack Overflow是常见的,作为一个全面的声明,将其指出为恶魔的行为,而不考虑具体情况.

它不一定要正确地同步.阻止异步以使其同步具有可能重要或可能完全无关的性能成本.这取决于具体情况.

死锁来自同时尝试进入相同单线程同步上下文的两个线程.避免这种可靠性的任何技术可以避免由阻塞引起的死锁.

在这里,所有调用.ConfigureAwait(false)的都是毫无意义的,因为你不在等待.

运行异步无效使用,因为并不是所有的任务都可以这样处理.

.GetAwaiter().GetResult()与Result / Wait()不同,它模仿等待异常传播行为.你需要决定是否要这样做. (所以研究这个行为是什么;不需要在这里重复一遍.)

此外,所有这些方法都具有相似的性能.他们将以某种方式分配OS事件并阻止它.这是昂贵的部分.我不知道哪种方法是绝对最便宜的.

我个人喜欢Task.Run(()=&DoSomethingAsync()).Wait();模式,因为它明确地避免了死锁,很简单,并不隐藏GetResult()可能隐藏的一些异常.但是您也可以使用GetResult().

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读