This question already has answers here:
Calling async methods from non-async code

(4个答案)


1年前关闭。




我有一个异步任务,需要同步调用(是的,不幸的是,这是不可避免的)。似乎有两种方法可以实现此目的-每种方法似乎都有效。因此,我不确定哪种方法最好,或者是否有更好的方法。

例如:
var meetings = Task.Run(() => GetTodaysMeetingsAsync()).GetAwaiter().GetResult();

var meetings = GetTodaysMeetingsAsync().GetAwaiter().GetResult();

如果有人可以解释为什么一种方法比另一种更好,那将不胜感激。谢谢!

最佳答案

当您使用Task.Run时,委托(delegate)的初始同步部分在线程池线程上运行,而仅().GetAwaiter().GetResult()将在同一线程上运行该同步部分。

使用Task.Run(...).GetAwaiter().GetResult()可以作为一种解决方法来运行异步代码并同步等待它,这不会导致异步死锁,而().GetAwaiter().GetResult()可以。请注意,它仍然不是“安全的”,因为您可能会在服务器上的线程池线程中进行阻塞,这可能导致负载时线程池耗尽。

如果您想运行Task返回方法,并且知道初始同步部分是微不足道的,并且您知道异步方法的其余部分将不会与SynchronizationContext一起运行,那么().GetAwaiter().GetResult()可以是一个微优化。仅当您确切知道自己在做什么时才这样做。

您怎么知道您没有SynchronizationContext运行?出于以下原因之一,SynchronizationContext.Current将为null:

  • 您知道您的代码正在没有一个应用程序模型(控制台应用程序,ASP.NET Core,Windows服务)下运行
  • 您已在当前堆栈中先前等待的不完整.ConfigureAwait(false)上使用了Task
  • 您已明确调用SynchronizationContext.SetSynchronizationContext(null)

  • 因此,您会发现,要考虑的事情很多,因此,通常来说,您几乎总是想使用Task.Run(...).GetAwaiter.GetResult()

    10-08 15:25