如何从非异步方法调用异步方法?
我有以下方法:
public string RetrieveHolidayDatesFromSource() { var result = this.RetrieveHolidayDatesFromSourceAsync(); /** Do stuff **/ var returnedResult = this.TransformResults(result.Result); /** Where result gets used **/ return returnedResult; } private async Task RetrieveHolidayDatesFromSourceAsync() { using (var httpClient = new HttpClient()) { var json = await httpClient.GetStringAsync(SourceURI); return json; } }
以上不起作用,似乎没有正确返回任何结果。 我不知道我在哪里错过强制等待结果的陈述? 我希望RetrieveHolidayDatesFromSource()方法返回一个字符串。
以下工作正常,但它是同步的,我相信它可以改进吗? 请注意,下面是同步的,我想将其更改为异步,但由于某种原因无法解决问题。
public string RetrieveHolidayDatesFromSource() { var result = this.RetrieveHolidayDatesFromSourceAsync(); /** Do Stuff **/ var returnedResult = this.TransformResults(result); /** This is where Result is actually used**/ return returnedResult; } private string RetrieveHolidayDatesFromSourceAsync() { using (var httpClient = new HttpClient()) { var json = httpClient.GetStringAsync(SourceURI); return json.Result; } }
我错过了什么吗?
注意:出于某种原因,当我断开上面的异步方法时,当它到达“var json = await httpClient.GetStringAsync(SourceURI)”这一行时,它就会超出断点而我无法返回到该方法。
我错过了什么吗?
是。 异步代码 – 本质上 – 暗示当操作正在进行时不使用当前线程。 同步代码 – 就其本质而言 – 意味着当前线程在操作正在进行时被阻塞。 这就是为什么从同步代码中调用异步代码甚至没有意义。 事实上,正如我在博客中描述的那样, 一种天真的方法(使用Result
/ Wait
)很容易导致死锁 。
首先要考虑的是:我的API 应该是同步还是异步? 如果它处理I / O(如本例所示),它应该是异步的 。 所以,这将是一个更合适的设计:
public async Task RetrieveHolidayDatesFromSourceAsync() { var result = await this.DoRetrieveHolidayDatesFromSourceAsync(); /** Do stuff **/ var returnedResult = this.TransformResults(result); /** Where result gets used **/ return returnedResult; }
正如我在异步最佳实践文章中所描述的那样,您应该“始终保持异步”。 如果你不这样做,你无论如何都不会从异步中获得任何好处,为什么还要烦恼?
但是,让我们说你最终会对异步感兴趣,但是现在你无法改变一切 ,你只想改变应用程序的一部分 。 这是一个非常普遍的情况。
在这种情况下,正确的方法是公开同步和异步API。 最终,在升级所有其他代码之后,可以删除同步API。 我在关于棕色异步开发的文章中探讨了这种场景的各种选择; 我个人最喜欢的是“bool参数hack”,它看起来像这样:
public string RetrieveHolidayDatesFromSource() { return this.DoRetrieveHolidayDatesFromSourceAsync(sync: true).GetAwaiter().GetResult(); } public Task RetrieveHolidayDatesFromSourceAsync() { return this.DoRetrieveHolidayDatesFromSourceAsync(sync: false); } private async Task DoRetrieveHolidayDatesFromSourceAsync(bool sync) { var result = await this.GetHolidayDatesAsync(sync); /** Do stuff **/ var returnedResult = this.TransformResults(result); return returnedResult; } private async Task GetHolidayDatesAsync(bool sync) { using (var client = new WebClient()) { return sync ? client.DownloadString(SourceURI) : await client.DownloadStringTaskAsync(SourceURI); } }
这种方法避免了代码重复,也避免了与其他“同步异步”反模式解决方案相同的死锁或重入问题。
请注意,我仍然会将生成的代码视为正确异步API路径上的“中间步骤”。 特别是,内部代码必须依赖于WebClient
(它支持同步和异步),而不是首选的HttpClient
(仅支持异步)。 一旦所有调用代码都被更改为使用RetrieveHolidayDatesFromSourceAsync
而不是RetrieveHolidayDatesFromSource
,那么我将重新访问并删除所有技术债务,将其更改为使用HttpClient
并仅为异步。
public string RetrieveHolidayDatesFromSource() { var result = this.RetrieveHolidayDatesFromSourceAsync().Result; /** Do stuff **/ var returnedResult = this.TransformResults(result.Result); /** Where result gets used **/ return returnedResult; }
如果将.Result添加到异步调用,它将执行并等待结果到达,强制它同步
更新:
private static string stringTest() { return getStringAsync().Result; } private static async Task getStringAsync() { return await Task.FromResult ("Hello"); } static void Main(string[] args) { Console.WriteLine(stringTest()); }
解决评论:这没有任何问题。
上述就是C#学习教程:如何从非异步方法调用异步方法?分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/1027124.html