为什么我会费心使用 Task.ConfigureAwait(continueOnCapturedContext: fal

本文关键字:ConfigureAwait continueOnCapturedContext fal Task 为什么 | 更新日期: 2023-09-27 18:36:54

请考虑以下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 行抛出异常,因为在等待之后,代码在非 UI 线程上执行。ConfigureAwait(false)在哪里有用?

为什么我会费心使用 Task.ConfigureAwait(continueOnCapturedContext: fal

Stephen Cleary有一个非常好的系列,你可以在这里找到,我引用了针对你的问题的文章:

大多数情况下,您不需要同步回"主"上下文。大多数异步方法在设计时都会考虑组合:它们等待其他操作,每个操作本身表示一个异步操作(可以由其他人组合)。在这种情况下,您希望通过调用 ConfigureAwait 并传递false来告诉等待者不要捕获当前上下文,例如:

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!";
}

此示例中要注意的重要一点是,异步方法调用的每个"级别"都有自己的上下文。 DownloadFileButton_Click在 UI 上下文中启动,并称为 DownloadFileAsyncDownloadFileAsync也从 UI 上下文中开始,但随后通过调用 ConfigureAwait(false) 脱离了其上下文。其余DownloadFileAsync在线程池上下文中运行。但是,当DownloadFileAsync完成并DownloadFileButton _Click恢复时,它会在 UI 上下文中恢复。

一个好的经验法则是使用ConfigureAwait(false)除非您知道自己确实需要上下文。

您应该始终在服务中使用它,因为服务应该与 UI 无关。

但是,如果出现以下情况,请勿在服务之外使用它

  • 需要操作 UI 或使用特定于 UI 的组件,例如调度程序或核心调度程序
  • 需要在 ASP.net 中使用 HttpContext.Current

在这些情况下,不应使用ConfigureAwait(continueOnCapturedContext: false)因为捕获当前上下文非常重要,否则应用将在尝试从非 UI 线程访问 UI 视图时崩溃

当你写await task;时,这等效于写await task.ConfigureAwait(continueOnCapturedContext: true);因为默认情况下continueOnCapturedContext为真。