我为什么要费心使用 Task.ConfigureAwait(continueOnCapturedContext: false);

Why would I bother to use Task.ConfigureAwait(continueOnCapturedContext: false);

考虑以下 windows 形式的代码:

private async void UpdateUIControlClicked(object sender, EventArgs e)
{
    this.txtUIControl.Text = "I will be updated after await - i hope!";
    await Task.Delay(5000).ConfigureAwait(continueOnCapturedContext: false);
    this.txtUIControl.Text = "I am updated now.";
}

这里在第3行抛出异常,因为await之后的代码是在非UI线程上执行的。 ConfigureAwait(false) 在哪里有用?

Stephen Cleary has a really good series on this you can find here,我引用了针对你问题的那篇文章:

Most of the time, you don’t need to sync back to the “main” context. Most async methods will be designed with composition in mind: they await other operations, and each one represents an asynchronous operation itself (which can be composed by others). In this case, you want to tell the awaiter to not capture the current context by calling ConfigureAwait and passing false, e.g.:

private async Task DownloadFileAsync(string fileName)
{
  // Use HttpClient or whatever to download the file contents.
  var fileContents = await DownloadFileContentsAsync(fileName).ConfigureAwait(false);

  // Note that because of the ConfigureAwait(false), we are not on the original context here.
  // Instead, we're running on the thread pool.

  // Write the file contents out to a disk file.
  await WriteToDiskAsync(fileName, fileContents).ConfigureAwait(false);

  // The second call to ConfigureAwait(false) is not *required*, but it is Good Practice.
}

// WinForms example (it works exactly the same for WPF).
private async void DownloadFileButton_Click(object sender, EventArgs e)
{
  // Since we asynchronously wait, the UI thread is not blocked by the file download.
  await DownloadFileAsync(fileNameTextBox.Text);

  // Since we resume on the UI context, we can directly access UI elements.
  resultTextBox.Text = "File downloaded!";
}

The important thing to note with this example is that each “level” of async method calls has its own context. DownloadFileButton_Click started in the UI context, and called DownloadFileAsync. DownloadFileAsync also started in the UI context, but then stepped out of its context by calling ConfigureAwait(false). The rest of DownloadFileAsync runs in the thread pool context. However, when DownloadFileAsync completes and DownloadFileButton_Click resumes, it does resume in the UI context.

A good rule of thumb is to use ConfigureAwait(false) unless you know you do need the context.

您应该在服务中始终使用它,因为服务应该 UI 不可知。

但是,如果

,请不要在服务之外使用它
  • 需要操纵 UI 或使用 UI 特定组件,例如 Dispatcher 或 CoreDispatcher
  • 需要在ASP.net
  • 中使用HttpContext.Current

在这些情况下,您不应使用 ConfigureAwait(false),因为捕获当前上下文很重要,否则应用程序会因尝试从 non-UI 线程访问 UI 视图而崩溃

await task;,相当于写awaittask.ConfigureAwait(true);。所以 true 是默认值。