81

考虑下面的 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) 在哪里有用?

4

2 回答 2

120

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

大多数时候,您不需要同步回“主”上下文。大多数异步方法在设计时都会考虑到组合:它们等待其他操作,每个操作都代表一个异步操作本身(可以由其他操作组合)。在这种情况下,您想通过调用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 上下文中启动,并调用DownloadFileAsync. DownloadFileAsync也是在 UI 上下文中开始的,但随后通过调用ConfigureAwait(false). 其余的DownloadFileAsync在线程池上下文中运行。但是,当DownloadFileAsync完成并DownloadFileButton_Click 恢复时,它在 UI 上下文中恢复。

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

于 2015-01-08T23:32:31.327 回答
15

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

但是,请不要在服务之外使用它,如果

  • 需要操作 UI 或使用 UI 特定组件,例如 Dispatcher 或 CoreDispatcher
  • 需要在 ASP.net 中使用 HttpContext.Current

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

写的时候await task;,就相当于写了await task.ConfigureAwait(true);。所以 true 是默认值。

于 2019-05-21T21:03:18.853 回答