我有一个async
方法:
public async Task<string> GenerateCodeAsync()
{
string code = await GenerateCodeService.GenerateCodeAsync();
return code;
}
我需要从一个同步的方法调用此方法。
我怎样才能做到这一点,而不必重复GenerateCodeAsync
以法为这个同步工作?
更新
然而,没有合理的解决方案中。
但是,我看到HttpClient
已经实现了这个模式
using (HttpClient client = new HttpClient())
{
// async
HttpResponseMessage responseAsync = await client.GetAsync(url);
// sync
HttpResponseMessage responseSync = client.GetAsync(url).Result;
}
您可以访问Result
的任务,这将导致你的线程阻塞,直到结果可用的属性:
string code = GenerateCodeAsync().Result;
注:在某些情况下,这可能会导致死锁:您的来电Result
块为主线,从而防止异步代码来执行的剩余部分。 您有以下选项,以确保不会发生这种情况:
你应该得到awaiter( GetAwaiter()
并结束等待异步任务完成( GetResult()
string code = GenerateCodeAsync().GetAwaiter().GetResult();
你应该能够得到这个工作使用委托,lambda表达式
private void button2_Click(object sender, EventArgs e)
{
label1.Text = "waiting....";
Task<string> sCode = Task.Run(async () =>
{
string msg =await GenerateCodeAsync();
return msg;
});
label1.Text += sCode.Result;
}
private Task<string> GenerateCodeAsync()
{
return Task.Run<string>(() => GenerateCode());
}
private string GenerateCode()
{
Thread.Sleep(2000);
return "I m back" ;
}
我需要调用从同步方法,此方法。
这是可能的GenerateCodeAsync().Result
或GenerateCodeAsync().Wait()
因为对方的回答暗示。 这将阻止当前线程,直到GenerateCodeAsync
已完成。
然而,你的问题被打上asp.net ,并且还留下了评论:
我希望有一个简单的解决方案,以为asp.net处理这比写代码那么多行更容易
我的观点是,你不应该在ASP.NET异步方法来阻止 。 这将减少你的web应用程序的可扩展性,并可能产生死锁(当await
中继续GenerateCodeAsync
发布到AspNetSynchronizationContext
)。 使用Task.Run(...).Result
卸载东西池线程,然后块将更加伤害的可扩展性,因为它会带来更多的+1线程来处理一个给定的HTTP请求。
ASP.NET有内置的异步方法,既可以通过异步控制器(在ASP.NET MVC和Web API)或直接通过支持AsyncManager
和PageAsyncTask
经典ASP.NET。 你应该使用它。 欲了解更多详情,请查看这个答案 。
微软身份具有扩展方法,其同步调用异步方法。 例如有GenerateUserIdentityAsync()方法和等于CreateIdentity()
如果你看一下UserManagerExtensions.CreateIdentity()它是这样的:
public static ClaimsIdentity CreateIdentity<TUser, TKey>(this UserManager<TUser, TKey> manager, TUser user,
string authenticationType)
where TKey : IEquatable<TKey>
where TUser : class, IUser<TKey>
{
if (manager == null)
{
throw new ArgumentNullException("manager");
}
return AsyncHelper.RunSync(() => manager.CreateIdentityAsync(user, authenticationType));
}
现在让我们看看AsyncHelper.RunSync做什么
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
var cultureUi = CultureInfo.CurrentUICulture;
var culture = CultureInfo.CurrentCulture;
return _myTaskFactory.StartNew(() =>
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = cultureUi;
return func();
}).Unwrap().GetAwaiter().GetResult();
}
所以,这是你的异步方法包装。 请不要读取结果的数据 - 这将有可能阻止ASP代码。
还有另一种方式 - 这是怀疑我,但你可以认为它太
Result r = null;
YourAsyncMethod()
.ContinueWith(t =>
{
r = t.Result;
})
.Wait();
为了防止死锁,我总是尝试使用Task.Run()
时,我有同步的是@Heinzi提到调用异步方法。
然而,该方法具有,如果异步方法使用的参数进行修改。 例如Task.Run(GenerateCodeAsync("test")).Result
给出了错误:
参数1:不能从转换“ System.Threading.Tasks.Task<string>
”到“System.Action”
这可以这样调用,而不是:
string code = Task.Run(() => GenerateCodeAsync("test")).Result;
另一种方法可能是,如果你想等到任务完成:
var t = GenerateCodeService.GenerateCodeAsync();
Task.WhenAll(t);
string code = t.Result;