ConfigureAwait(false) 的性能测试

3

我在各处阅读到,应该使用ConfigureAwait(false)来避免死锁并提高性能。我们的应用程序中正在使用ConfigureAwait,但是可能会删除ConfigureAwaits,因为它会导致不同线程的执行上下文。

不同线程的执行上下文有时会导致翻译出现问题。因为在不同的执行上下文中无法访问当前区域设置和当前用户界面区域设置。

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

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 是否是一个非常糟糕的想法?


2
你不应该需要使用“ConfigureAwait(false)”来防止死锁 - 这些死锁只会在您阻塞异步代码时发生,而这是不应该做的。 - Ant P
3
如果您正在使用类似控制台应用程序之类的东西进行测试 - 无论如何都不会有任何影响,因为没有上下文。 - Evk
我会忽略性能差异。如果在.NET 4.6上看到不同的“CurrentCulture”/“CurrentUICulture”值,则这是一个错误,应该报告为此类错误。 - Stephen Cleary
2个回答

19
不要盲目使用 ConfigureAwait 来提高性能。在编写代码(通常是库代码)时,只有在恢复到相同的线程/同步上下文无关紧要时才使用它。如果在正确的线程/同步上下文上恢复很重要,则会破坏您的代码,然后即使速度再快也没有用处。ConfigureAwait(false)

6
无论使用何种方式来实现async-await, 它都不是为了提高性能,而是为了响应和可用性。
在客户端UI上,如WinForms、WPF或UWP,它主要是为了提高响应速度。你可以在IO和CPU绑定的操作上使用async-await在UI线程之外执行工作, 并使用ConfigureAwait(false)明确避免返回到UI线程。
在ASP.NET (.NET Framework, 而不是.NET Core)上,它主要是为了提高可用性。你可以在IO操作上使用async-await释放线程以处理其他请求,并使用ConfigureAwait(false)避免设置返回线程为HTTP上下文线程。
但由于你总是做更多的工作,每个逻辑操作所需的时间会更长。
在客户端UI上,用户仍然能够使用应用程序,或者至少不会在标题栏和任务管理器中看到"未响应"的字样。
在ASP.NET上,由于有更多的线程可用来处理请求,在负载较重时,它会更快,因为请求被允许立即开始工作,而不是被阻塞在请求队列中。

在ASP.NET(.NET Framework,而不是.NET Core)中,为什么要加上“不是.NET Core”的注释?只是好奇。 - Alex from Jitbit
ASP.NET Core没有上下文亲和性,也不像由同步上下文管理的HttpContext.Current那样思考。 - Paulo Morgado

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接