同步调用asynchronous方法
我有一个async
方法:
public async Task<string> GenerateCodeAsync() { string code = await GenerateCodeService.GenerateCodeAsync(); return code; }
我需要从同步方法调用这个方法。
我怎样才能做到这一点,而不必重复GenerateCodeAsync
方法,以使其同步工作?
更新
但没有find合理的解决办法
但是,我看到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
调用会阻塞主线程,从而阻止执行其余的asynchronous代码。 您有以下选项来确保不会发生这种情况:
- 将
.ConfigureAwait(false)
添加到您的库方法 或 -
在线程池线程中明确执行你的asynchronous方法并等待它完成:
string code = Task.Run(GenerateCodeAsync).Result;
您应该得到awaiter( GetAwaiter()
)并结束等待asynchronous任务( GetResult()
)的完成。
string code = GenerateCodeAsync().GetAwaiter().GetResult();
你应该可以使用委托,lambdaexpression式来完成这个任务
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标记的,你也留下了评论:
我希望得到一个更简单的解决scheme,认为asp.net处理这一点比编写这么多行代码容易得多
我的意思是,你不应该阻止在ASP.NET中的asynchronous方法。 这将减less您的Web应用程序的可伸缩性,并可能创build一个死锁(当GenerateCodeAsync
内部的await
继续发布到AspNetSynchronizationContext
)。 使用Task.Run(...).Result
将某些内容卸载到一个池线程,然后阻塞会更多地损害可伸缩性,因为它会导致多出一个线程来处理给定的HTTP请求。
ASP.NET通过asynchronous控制器(在ASP.NET MVC和Web API中)或直接通过经典ASP.NET中的AsyncManager
和PageAsyncTask
来内置对asynchronous方法的支持。 你应该使用它。 有关更多详细信息,请查看此答案 。
Microsoft Identity具有同步调用asynchronous方法的扩展方法。 例如,有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的function
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(); }
所以,这是你的asynchronous方法的包装。 请不要从结果中读取数据 – 它可能会阻止您的代码在ASP中。
还有另外一种方法 – 这对我来说很可疑,但你也可以考虑
Result r = null; YourAsyncMethod() .ContinueWith(t => { r = t.Result; }) .Wait();
Task task1 = Task.Factory.StartNew(() => System.Threading.Thread.Sleep(3000)); task1.Wait(); Messagebox.Show("task1 completed"); Task task2 = Task.Factory.StartNew(() => System.Threading.Thread.Sleep(3000)); task2.Wait(); Messagebox.Show("task2 completed");
这帮助我下面的脚本只有在task1完成后才能继续工作。
- 任务sorting和re-entracy
- WebAPI中长时间运行的任务
- 在TPL Task对象上调用Dispose()是否可以接受?
- 创build一个完成的任务
- 同步等待asynchronous操作,为什么Wait()在这里冻结程序
- 捕获asynchronous方法引发的exception
- Reactive Framework,PLINQ,TPL和并行扩展如何相互关联?
- UnobservedTaskException被抛出,但它由TaskScheduler.UnobservedTaskException处理程序和一个continuation OnlyOnFaulted处理程序处理
- TaskCompletionSource:何时使用SetResult()与TrySetResult()等