我有一个公共异步无效Foo()方法,我想从同步方法调用。到目前为止,我从MSDN文档中看到的都是通过异步方法调用异步方法,但我的整个程序并不是用异步方法构建的。
这可能吗?
下面是一个从异步方法调用这些方法的例子: 演练:使用Async和Await访问Web (c#和Visual Basic)
现在我正在研究从sync方法调用这些async方法。
我有一个公共异步无效Foo()方法,我想从同步方法调用。到目前为止,我从MSDN文档中看到的都是通过异步方法调用异步方法,但我的整个程序并不是用异步方法构建的。
这可能吗?
下面是一个从异步方法调用这些方法的例子: 演练:使用Async和Await访问Web (c#和Visual Basic)
现在我正在研究从sync方法调用这些async方法。
当前回答
现在,您可以使用源生成器使用同步方法生成器库(nuget)创建方法的同步版本。
使用方法如下:
[Zomp.SyncMethodGenerator.CreateSyncVersion]
public async void FooAsync()
它会生成Foo方法,你可以同步调用。
其他回答
斯蒂芬·克利里的回答;
这种方法应该不会导致死锁(假设 ProblemMethodAsync不发送更新到UI线程或任何东西 像这样)。它假设可以在对象上调用ProblemMethodAsync 线程池线程,这并不总是这样。
https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
这就是方法;
线程池攻击与阻塞攻击类似的方法是 将异步工作卸载到线程池,然后阻塞 产生的任务。使用此黑客的代码看起来像下面的代码 如图7所示。 图7线程池攻击的代码 c#
public sealed class WebDataService : IDataService
{
public string Get(int id)
{
return Task.Run(() => GetAsync(id)).GetAwaiter().GetResult();
}
public async Task<string> GetAsync(int id)
{
using (var client = new WebClient())
return await client.DownloadStringTaskAsync(
"https://www.example.com/api/values/" + id);
}
}
Task的调用。Run在线程池上执行异步方法 线程。在这里,它将在没有上下文的情况下运行,从而避免 死锁。这种方法的一个问题是异步性 方法不能依赖于在特定上下文中执行。所以,它 不能使用UI元素或ASP。净HttpContext.Current。
您可以从同步代码中调用任何异步方法,直到您需要等待它们,在这种情况下,它们也必须被标记为异步。
正如很多人在这里建议的那样,您可以在同步方法中对结果任务调用Wait()或Result,但最终会在该方法中进行阻塞调用,这在某种程度上违背了异步的目的。
如果你真的不能让你的方法异步,你不想锁定同步方法,那么你将不得不使用一个回调方法,把它作为参数传递给任务上的ContinueWith()方法。
受到其他一些答案的启发,我创建了以下简单的帮助方法:
public static TResult RunSync<TResult>(Func<Task<TResult>> method)
{
var task = method();
return task.GetAwaiter().GetResult();
}
public static void RunSync(Func<Task> method)
{
var task = method();
task.GetAwaiter().GetResult();
}
调用方法如下(取决于你是否返回值):
RunSync(() => Foo());
var result = RunSync(() => FooWithResult());
注意,原始问题public async void Foo()中的签名是不正确的。它应该是公共async Task Foo(),因为对于不返回值的异步方法,应该返回Task而不是void(是的,有一些罕见的例外)。
public async Task<string> StartMyTask()
{
await Foo()
// code to execute once foo is done
}
static void Main()
{
var myTask = StartMyTask(); // call your method which will return control once it hits await
// now you can continue executing code here
string result = myTask.Result; // wait for the task to complete to continue
// use result
}
您将‘await’关键字读为“启动这个长时间运行的任务,然后将控制权返回给调用方法”。长时间运行的任务完成后,它将执行后面的代码。await之后的代码类似于过去的CallBack方法。最大的区别是逻辑流没有中断,这使得读写更容易。
var result = Task.Run(async () => await configManager.GetConfigurationAsync()).ConfigureAwait(false);
OpenIdConnectConfiguration config = result.GetAwaiter().GetResult();
或者用这个:
var result=result.GetAwaiter().GetResult().AccessToken