为什么我会费心使用 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)在哪里有用?
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 上下文中启动,并称为DownloadFileAsync
。DownloadFileAsync
也从 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
为真。