一尘不染

调用ConfigureAwait获取所有服务器端代码的最佳实践

c#

当您拥有服务器端代码(即某些代码ApiController)并且函数是异步的(因此它们返回)Task<SomeObject>时,是否在任何时候都等待调用的函数是否被视为最佳实践ConfigureAwait(false)

我已经读到它具有更高的性能,因为它不必将线程上下文切换回原始线程上下文。但是,对于ASP.NET Web
Api,如果您的请求是在一个线程上传入的,并且您等待某个函数并调用ConfigureAwait(false),则在返回ApiController函数的最终结果时,该函数可能会将您置于另一个线程上。

我在下面输入了一个我正在谈论的例子:

public class CustomerController : ApiController
{
    public async Task<Customer> Get(int id)
    {
        // you are on a particular thread here
        var customer = await SomeAsyncFunctionThatGetsCustomer(id).ConfigureAwait(false);

        // now you are on a different thread!  will that cause problems?
        return customer;
    }
}

阅读 371

收藏
2020-05-19

共1个答案

一尘不染

更新: ASP.NET
Core没有SynchronizationContext
。如果您使用的是ASP.NET
Core,则无论是否使用都ConfigureAwait(false)无所谓。

对于ASP.NET“完全”或“经典”之类的东西,其余答案仍然适用。

原始帖子(适用于非Core ASP.NET):

该ASP.NET团队的视频提供了有关async在ASP.NET
上使用的最佳信息。

我已经读到它具有更高的性能,因为它不必将线程上下文切换回原始线程上下文。

对于UI应用程序,这是正确的,在该应用程序中,您只需要“同步”回一个UI线程。

在ASP.NET中,情况要复杂一些。当一个async方法恢复执行时,它将从ASP.NET线程池中的线程。如果使用禁用了上下文捕获ConfigureAwait(false),则线程将继续直接直接执行该方法。如果不禁用上下文捕获,则线程将重新输入请求上下文,然后继续执行该方法。

因此ConfigureAwait(false),不会为您节省ASP.NET中的线程跳转;它确实为您节省了重新输入请求上下文的时间,但这通常非常快。如果您尝试对请求进行少量并行处理,则ConfigureAwait(false)
可能 会很有用,但是TPL实际上更适合大多数情况。

但是,对于ASP.NET Web
Api,如果您的请求是在一个线程上发出的,并且您在等待某个函数并调用ConfigureAwait(false),则当您返回ApiController函数的最终结果时,这有可能使您进入另一个线程。

实际上,只要这样做await就可以做到。一旦您的async方法达到await,该 方法将 被阻止,但 线程
将返回线程池。当该方法准备好继续时,将从线程池中抢夺任何线程,并将其用于恢复该方法。

ConfigureAwaitASP.NET 的唯一区别是恢复该方法时该线程是否进入请求上下文。

在我的MSDN文章SynchronizationContextasync简介博客中,我有更多的背景信息。

2020-05-19