我有一个 async
方法:
public async Task<string> GenerateCodeAsync()
{
string code = await GenerateCodeService.GenerateCodeAsync();
return code;
}
我需要从同步方法调用此方法 .
如何在不必复制 GenerateCodeAsync
方法的情况下执行此操作以使其同步工作?
Update
然而找不到合理的解决方案
但是,我看到 HttpClient
已经实现了这种模式
using (HttpClient client = new HttpClient())
{
// async
HttpResponseMessage responseAsync = await client.GetAsync(url);
// sync
HttpResponseMessage responseSync = client.GetAsync(url).Result;
}
6 回答
您可以访问任务的
Result
属性,这将导致您的线程阻塞,直到结果可用:注意:在某些情况下,这可能会导致死锁:您对
Result
的调用会阻塞主线程,从而阻止执行其余的异步代码 . 您有以下选项可确保不会发生这种情况:Add .ConfigureAwait(false) to your library method或
在线程池线程中显式执行您的异步方法并等待它完成:
你应该得到awaiter(
GetAwaiter()
)并结束等待完成异步任务(GetResult()
) .有可能是
GenerateCodeAsync().Result
或GenerateCodeAsync().Wait()
,正如另一个答案所暗示的那样 . 这将阻止当前线程,直到GenerateCodeAsync
完成 .但是,您的问题标有asp.net,您还留下了评论:
我的观点是,你_____1383_在ASP.NET中的异步方法 . 这将降低Web应用程序的可伸缩性,并可能造成死锁(当
GenerateCodeAsync
中的await
延续发布到AspNetSynchronizationContext
时) . 使用Task.Run(...).Result
将某些内容卸载到池线程然后阻塞将进一步损害可伸缩性,因为它会产生一个以上的线程来处理给定的HTTP请求 .ASP.NET内置了对异步方法的支持,可以通过异步控制器(在ASP.NET MVC和Web API中),也可以直接通过经典ASP.NET中的
AsyncManager
和PageAsyncTask
. 你应该使用它 . 有关更多详细信息,请查看this answer .为了防止死锁,我总是尝试使用
Task.Run()
,当我必须同步调用@Heinzi提到的异步方法时 .但是,如果异步方法使用参数,则必须修改该方法 . 例如
Task.Run(GenerateCodeAsync("test")).Result
给出错误:这可以像这样调用:
Microsoft Identity具有同步调用异步方法的扩展方法 . 例如,有GenerateUserIdentityAsync()方法并且等于CreateIdentity()
如果你看一下UserManagerExtensions.CreateIdentity(),它看起来像这样:
现在让我们看看AsyncHelper.RunSync的功能
所以,这是异步方法的包装器 . 请不要从结果中读取数据 - 它可能会阻止您在ASP中的代码 .
还有另一种方式 - 这对我来说很可疑,但你也可以考虑它
您应该能够使用委托,lambda表达式完成此操作