Cat*_*lin 216 c# asp.net asynchronous task-parallel-library async-await
我有一个async
方法:
public async Task<string> GenerateCodeAsync()
{
string code = await GenerateCodeService.GenerateCodeAsync();
return code;
}
Run Code Online (Sandbox Code Playgroud)
我需要从同步方法中调用此方法.
如何在不必复制GenerateCodeAsync
方法的情况下执行此操作以使其同步工作?
更新
然而找不到合理的解决方案
但是,我看到HttpClient
已经实现了这种模式
using (HttpClient client = new HttpClient())
{
// async
HttpResponseMessage responseAsync = await client.GetAsync(url);
// sync
HttpResponseMessage responseSync = client.GetAsync(url).Result;
}
Run Code Online (Sandbox Code Playgroud)
Hei*_*nzi 266
您可以访问Result
任务的属性,这将导致您的线程阻塞,直到结果可用:
string code = GenerateCodeAsync().Result;
Run Code Online (Sandbox Code Playgroud)
注意:在某些情况下,这可能会导致死锁:您调用Result
阻塞主线程,从而阻止执行异步代码的其余部分.您有以下选项可确保不会发生这种情况:
.ConfigureAwait(false)
到您的库方法 或在线程池线程中显式执行您的异步方法并等待它完成:
string code = Task.Run(GenerateCodeAsync).Result;
Run Code Online (Sandbox Code Playgroud)小智 53
您应该获取awaiter(GetAwaiter()
)并结束等待异步任务(GetResult()
)的完成.
string code = GenerateCodeAsync().GetAwaiter().GetResult();
Run Code Online (Sandbox Code Playgroud)
Fai*_*yaz 30
您应该能够使用委托,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" ;
}
Run Code Online (Sandbox Code Playgroud)
nos*_*tio 20
我需要从同步方法中调用此方法.
正如另一个答案所暗示的那样,它可能与GenerateCodeAsync().Result
或GenerateCodeAsync().Wait()
有关.这将阻止当前线程直到GenerateCodeAsync
完成.
但是,你的问题用asp.net标记,你也留下了评论:
我希望有一个更简单的解决方案,认为asp.net处理这个比编写这么多行代码要容易得多
我的观点是,你不应该阻止 ASP.NET中的异步方法.这将降低Web应用程序的可伸缩性,并可能造成死锁(当发布await
内部延续时).使用将某些内容卸载到池线程然后阻塞会进一步损害可伸缩性,因为它会导致+1更多线程来处理给定的HTTP请求.GenerateCodeAsync
AspNetSynchronizationContext
Task.Run(...).Result
ASP.NET有内置的异步方法的支持,无论是通过异步控制器(在ASP.NET MVC和Web API)或直接通过AsyncManager
和PageAsyncTask
经典ASP.NET.你应该使用它.有关详细信息,请查看此答案.
Vit*_*nov 18
Microsoft Identity具有同步调用异步方法的扩展方法.例如,有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));
}
Run Code Online (Sandbox Code Playgroud)
现在让我们看看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();
}
Run Code Online (Sandbox Code Playgroud)
所以,这是异步方法的包装器.请不要从结果中读取数据 - 它可能会阻止您在ASP中的代码.
还有另外一种方式 - 这对我来说很可疑,但你也可以考虑它
Result r = null;
YourAsyncMethod()
.ContinueWith(t =>
{
r = t.Result;
})
.Wait();
Run Code Online (Sandbox Code Playgroud)
kam*_*eet 13
该线程上的大多数答案要么很复杂,要么会导致死锁。
下面的方法很简单,它会避免死锁,因为我们正在等待任务完成,然后才得到它的结果——
var task = Task.Run(() => GenerateCodeAsync());
task.Wait();
string code = task.Result;
Run Code Online (Sandbox Code Playgroud)
此外,这是对 MSDN 文章的引用,该文章谈论了完全相同的事情- https://blogs.msdn.microsoft.com/jpsanders/2017/08/28/asp-net-do-not-use-task-result-主上下文/
为了防止死锁,我总是尝试使用Task.Run()
@Heinzi提到的同步调用异步方法.
但是,如果异步方法使用参数,则必须修改该方法.例如,Task.Run(GenerateCodeAsync("test")).Result
给出错误:
参数1:无法从'
System.Threading.Tasks.Task<string>
' 转换为'System.Action'
这可以像这样调用:
string code = Task.Run(() => GenerateCodeAsync("test")).Result;
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
208182 次 |
最近记录: |