为什么我要费心使用 Task.ConfigureAwait(continueOnCapturedContext: false); [英] Why would I bother to use Task.ConfigureAwait(continueOnCapturedContext: false);

查看:14
本文介绍了为什么我要费心使用 Task.ConfigureAwait(continueOnCapturedContext: false);的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑下面的窗体代码:

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) 在哪里有用?

Here the exception is thrown at the 3rd line because after await the code is executed on non-UI thread. Where ConfigureAwait(false) is useful?

推荐答案

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

Stephen Cleary has a really good series on this you can find here, I quoted the piece specific to your question:

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

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

这个例子需要注意的重要一点是异步方法调用的每个级别"都有自己的上下文.DownloadFileButton_Click 在 UI 上下文中启动,并调用 DownloadFileAsync.DownloadFileAsync 也在 UI 上下文中启动,但随后通过调用 ConfigureAwait(false) 退出其上下文.DownloadFileAsync 的其余部分在线程池上下文中运行.但是,当 DownloadFileAsync 完成并且 DownloadFileButton_Click 恢复时,它确实在 UI 上下文中恢复.

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.

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

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

这篇关于为什么我要费心使用 Task.ConfigureAwait(continueOnCapturedContext: false);的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆