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

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

问题描述

请考虑以下Windows窗体代码:

Consider the following code of windows forms:

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

此处在第三行引发了异常,因为在等待之后,代码将在非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 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天全站免登陆