ConfigureAwait(false) 性能测试

Posted

技术标签:

【中文标题】ConfigureAwait(false) 性能测试【英文标题】:ConfigureAwait(false) performance test 【发布时间】:2017-11-08 13:29:38 【问题描述】:

我读到的所有地方都应该使用ConfigureAwait(false) 来避免死锁和出于性能原因。我们在我们的应用程序中使用ConfigureAwait。但可能会删除 ConfigureAwaits,因为它会导致不同线程的执行上下文。

不同线程的执行上下文导致(有时)翻译问题。由于 currentculture 和 currentUICulture 中的设置文化在不同的执行上下文中无法访问。

我已经用下面的代码对其进行了一些测试。它没有任何性能差异。我知道这不是一个好的测试,因为这个简单的测试使用的线程并不多。

static async Task MyMethodAsync()

  Stopwatch stopwatch = new Stopwatch();
  stopwatch.Start();
  for (int i = 0; i < 1000; i++)
  
     await Task.Delay(10);
     await Task.Delay(10).ConfigureAwait(continueOnCapturedContext: false);
  
  stopwatch.Stop();
  Console.WriteLine("Await: " + stopwatch.Elapsed.ToString());


static async Task MyMethodAsyncNoAwait()

  Stopwatch stopwatch = new Stopwatch();
  stopwatch.Start();
  for (int i = 0; i < 1000; i++)
  
     await Task.Delay(10);
     await Task.Delay(10);
  
  stopwatch.Stop();
  Console.WriteLine(stopwatch.Elapsed.ToString());

我应该如何正确测试这个?删除所有 ConfigureAwaits 真的是个坏主意吗?

【问题讨论】:

您不应该需要ConfigureAwait(false) 来防止死锁——这些死锁只会在您阻塞异步代码时首先发生,而您不应该这样做。 如果您使用控制台应用程序之类的东西进行测试 - 无论如何它不会有任何区别,因为没有上下文。 我会忽略性能差异。如果您在 .NET 4.6 上看到不同的 CurrentCulture / CurrentUICulture 值,那么这是一个错误,应该这样报告。 【参考方案1】:

不要为了性能而盲目使用ConfigureAwait。在编写代码(通常是库代码)时使用它,在同一线程/同步上下文中恢复无关紧要。如果在正确的线程/同步上下文中恢复确实很重要,ConfigureAwait(false) 会破坏你的代码,然后它可能有多快都没关系。

【讨论】:

【参考方案2】:

您对async-await 所做的一切与性能无关,而是与响应能力和可用性有关。

在 WinForms、WPF 或 UWP 等客户端 UI 上,它与响应能力有关。您在 IO 和 CPU 绑定操作上使用 async-await 在 UI 线程之外执行工作,并使用 ConfigureAwait(false) 明确避免返回到该 UI 线程。

在 ASP.NET(.NET Framework,而不是 .NET Core)上,它与可用性有关。您在 IO 操作上使用 async-await 以释放线程以处理其他请求,并使用 ConfigureAwait(false) 避免将返回线程设置为 HTTP 上下文线程。

但是因为你总是做更多的工作,每个逻辑操作都会花费更长的时间。

在客户端 UI 上,用户仍然可以使用应用程序,或者至少不会在标题栏和任务管理器上看到“没有响应”的短语。

在 ASP.NET 上,由于有更多线程可用于处理请求,因此在负载较重时,它会更快,因为允许请求立即开始工作,而不是在请求队列中被阻塞。

【讨论】:

以上是关于ConfigureAwait(false) 性能测试的主要内容,如果未能解决你的问题,请参考以下文章

为整个项目/dll 设置 ConfigureAwait(false)

ConfigureAwait(false) 与将同步上下文设置为 null

您可以在没有线程安全的情况下使用 ConfigureAwait(false) 吗?

ConfigureAwait(false) 不会使延续代码在另一个线程中运行

ConfigureAwait(false) 维护线程身份验证,但默认情况下不

为啥总是推荐在每一行上写 ConfigureAwait(false) 并且我真的需要它吗?