在ASP.NET 4.5应用程序中,哪一个更适合从同步方法调用异步方法?
var result = Task.Run(() => SomethingAsync()).GetAwaiter().GetResult();
// or
var temp = SynchronizationContext.Current;
try
{
SynchronizationContext.SetSynchronizationContext(null);
return SomethingAsync().GetAwaiter().GetResult();
}
finally
{
SynchronizationContext.SetSynchronizationContext(temp);
}
注意:是的,我知道我应该一直使用async/await
,但是我在询问ASP.NET核心的底部和外部过滤器和剃刀视图不是异步的,所以如果我想从过滤器或剃刀视图调用异步方法,我需要以某种方式同步它。由于SomethingAsync().GetAwaiter().GetResult()
,仅使用SynchronizationContext
会导致死锁,因此我需要一种方法来运行此代码而不使用SynchronizationContext
。
修改 这是一个简单的帮助器类,可以干净地包装它:
public static class Async
{
public static T Run<T>(Func<Task<T>> func)
{
var context = SynchronizationContext.Current;
if (context == null)
{
return func().GetAwaiter().GetResult();
}
SynchronizationContext.SetSynchronizationContext(null);
try
{
return func().GetAwaiter().GetResult();
}
finally
{
SynchronizationContext.SetSynchronizationContext(context);
}
}
public static void Run(Func<Task> func)
{
var context = SynchronizationContext.Current;
if (context == null)
{
func().GetAwaiter().GetResult();
return;
}
SynchronizationContext.SetSynchronizationContext(null);
try
{
func().GetAwaiter().GetResult();
}
finally
{
SynchronizationContext.SetSynchronizationContext(context);
}
}
}
// Example
var result = Async.Run(() => GetSomethingAsync("blabla"));
答案 0 :(得分:1)
显然,同步调用异步代码并不理想,但是如果你能帮助它,我必须说避免Task.Run
。
Task.Run
在SetSynchronizationContext(null)
上面有很多问题:
SynchronizationContext
它会使您同步阻止整个任务返回功能,而不仅仅是需要它的区域,您每次使用时也会倍增您的问题它。您最终会对更长阻止异步代码进行阻止,这肯定不是您想要的。Task.Run
现在正在引入阻止异步,而SetSynchronizationContext(null)
将不会花费你任何东西。 最后,当您阻止Task
返回功能时,另一个建议是use something like AsyncPump.Run
(Stephen Toub)。它以阻塞线程运行排队延续的方式等待,这样你就不会支付多个并发线程的价格而且没有死锁,显然仍然不如一直使用异步一样好。 / p>