如何在C#中同步方法调用异步方法? [英] How to call asynchronous method from synchronous method in C#?

查看:698
本文介绍了如何在C#中同步方法调用异步方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个公共异步无效美孚()的方法,我想从同步方法调用。到目前为止,所有我从MSDN文档看出呼吁通过异步方法异步方法,但我的整个程序不与异步方法建造的。

I have a public async void Foo() method that I want to call from synchronous method. So far all I have seen from MSDN documentation is calling async methods via async methods, but my whole program is not built with async methods.

这甚至可能吗?

下面是从调用异步方法,这些方法的一个例子:<一href=\"http://msdn.microsoft.com/en-us/library/hh300224(v=vs.110).aspx\">http://msdn.microsoft.com/en-us/library/hh300224(v=vs.110).aspx

Here's one example of calling these methods from an asynchronous method: http://msdn.microsoft.com/en-us/library/hh300224(v=vs.110).aspx

现在,我寻找到从调用方法同步异步这些方法。

Now I'm looking into calling these async methods from sync methods.

推荐答案

异步编程并通过code基成长。它已经<一个href=\"http://blogs.msdn.com/b/lucian/archive/2011/04/15/async-ctp-refresh-design-changes.aspx\">compared一个僵尸病毒。最好的解决办法是允许它成长,但有时这是不可能的。

Asynchronous programming does "grow" through the code base. It has been compared to a zombie virus. The best solution is to allow it to grow, but sometimes that's not possible.

我在 Nito.AsyncEx 库写了几个类型的处理部分异步code基地。有没有解决方案,在任何情况下工作的。

I have written a few types in my Nito.AsyncEx library for dealing with a partially-asynchronous code base. There's no solution that works in every situation, though.

解决方案A

如果你有一个不需要回同步到它的背景,那么你可以使用一个简单的异步方法 Task.WaitAndUnwrapException

If you have a simple asynchronous method that doesn't need to synchronize back to its context, then you can use Task.WaitAndUnwrapException:

var task = MyAsyncMethod();
var result = task.WaitAndUnwrapException();

您做的的要使用 Task.Wait Task.Result ,因为它们包装在 AggregateException 例外。

You do not want to use Task.Wait or Task.Result because they wrap exceptions in AggregateException.

此解决方案,如果 MyAsyncMethod 不同步回它的上下文才适用。换句话说,每个等待 MyAsyncMethod 结束ConfigureAwait(假)。这意味着它不能更新任何UI元素或访问ASP.NET请求上下文。

This solution is only appropriate if MyAsyncMethod does not synchronize back to its context. In other words, every await in MyAsyncMethod should end with ConfigureAwait(false). This means it can't update any UI elements or access the ASP.NET request context.

解决方案B

如果 MyAsyncMethod 确实需要同步回它的上下文,那么你可以使用 AsyncContext.RunTask 提供一个嵌套的上下文:

If MyAsyncMethod does need to synchronize back to its context, then you may be able to use AsyncContext.RunTask to provide a nested context:

var result = AsyncContext.RunTask(MyAsyncMethod).Result;


*更新2014年4月14日:在最近的版本库中的API是为如下:


*Update 4/14/2014: In more recent versions of the library the API is as follows:

var result = AsyncContext.Run(MyAsyncMethod);


(这是确定在这个例子中使用 Task.Result ,因为 RunTask 将传播任务例外)。

您可能需要的原因 AsyncContext.RunTask 而不是 Task.WaitAndUnwrapException 是因为一个相当微妙的僵局可能性出现这种情况的的WinForms / WPF / SL / ASP.NET:

The reason you may need AsyncContext.RunTask instead of Task.WaitAndUnwrapException is because of a rather subtle deadlock possibility that happens on WinForms/WPF/SL/ASP.NET:


  1. 的同步方法调用异步方法,获得工作

  2. 同步方法确实对工作 A阻塞等待。

  3. 异步方法使用等待没有 ConfigureAwait

  4. 工作不能在这种情况下完成,因为它只有在异步方法完成完成;在异步方法无法完成,因为它正试图安排其延续到的SynchronizationContext ,和WinForms / WPF / SL / ASP.NET将不允许继续运行,因为同步方法已经在上下文中运行。

  1. A synchronous method calls an async method, obtaining a Task.
  2. The synchronous method does a blocking wait on the Task.
  3. The async method uses await without ConfigureAwait.
  4. The Task cannot complete in this situation because it only completes when the async method is finished; the async method cannot complete because it is attempting to schedule its continuation to the SynchronizationContext, and WinForms/WPF/SL/ASP.NET will not allow the continuation to run because the synchronous method is already running in that context.

这也是为什么这是一个好主意,用 ConfigureAwait(假)每个异步方法中尽可能多越好。

This is one reason why it's a good idea to use ConfigureAwait(false) within every async method as much as possible.

C液

AsyncContext.RunTask 不会在每一个场景中工作。例如,如果异步方法等待的东西,需要一个UI事件来完成,那么你甚至嵌套的背景下发生死锁。在这种情况下,你可以启动异步线程池的方法:

AsyncContext.RunTask won't work in every scenario. For example, if the async method awaits something that requires a UI event to complete, then you'll deadlock even with the nested context. In that case, you could start the async method on the thread pool:

var task = TaskEx.RunEx(async () => await MyAsyncMethod());
var result = task.WaitAndUnwrapException();

然而,这种解决方案需要一个 MyAsyncMethod 将在线程池环境中工作。所以,它不能更新UI元素或访问ASP.NET请求上下文。而在这种情况下,你可能也添加 ConfigureAwait(假)等待语句和使用的解决方案A.

However, this solution requires a MyAsyncMethod that will work in the thread pool context. So it can't update UI elements or access the ASP.NET request context. And in that case, you may as well add ConfigureAwait(false) to its await statements, and use solution A.

这篇关于如何在C#中同步方法调用异步方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆