为什么我懒得使用Task.ConfigureAwait(continueOnCapturedContext:false);

时间:2015-01-08 22:57:10

标签: c# async-await synchronizationcontext

考虑以下Windows窗体代码:

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

这里异常是在第3行引发的,因为在等待代码在非UI线程上执行之后。 ConfigureAwait(false)有用吗?

2 个答案:

答案 0 :(得分:72)

Stephen Cleary has a really good series on this you can find here,我引用了你问题的具体内容:

  

大多数情况下,您不需要同步回“主”上下文。大多数异步方法都将在设计时考虑到组合:它们等待其他操作,每个操作本身代表一个异步操作(可以由其他操作组成)。在这种情况下,您希望通过调用 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 _点击恢复时, 会在UI上下文中恢复。

     

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

答案 1 :(得分:0)

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

但是,请勿在服务之外使用它

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

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

当您写await task;时,相当于写等待task.ConfigureAwait(true);。默认是true。