为什么我会打扰使用Task.ConfigureAwait(continueOnCapturedContext:false);

考虑下面的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."; } 

这里在第三行抛出exception,因为在等待代码在非UI线程上执行之后。 ConfigureAwait(false)有用吗?

斯蒂芬·克利里有一个非常好的系列,你可以在这里find ,我引用了你的问题的具体部分:

大多数情况下,您不需要同步回到“主”上下文。 大多数asynchronous方法的devise都是考虑到组合:它们等待其他操作,而每一个操作本身代表一个asynchronous操作(可由其他操作组成)。 在这种情况下,您要通过调用ConfigureAwait并传递false来告诉awaiter 捕获当前上下文,例如:

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

这个例子中要注意的重要一点是,asynchronous方法调用的每个“级别”都有自己的上下文。 DownloadFileButton_Click在UI上下文中启动,并称为DownloadFileAsyncDownloadFileAsync也在UI上下文中启动,但是通过调用ConfigureAwait(false)脱离了上下文。 DownloadFileAsync的其余部分在线程池上下文中运行。 但是,当DownloadFileAsync完成, DownloadFileButton _Click继续时,它在UI上下文恢复。

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

如果ConfigureAwait初始化为false ,代码将不会在主线程(UI线程)上运行,但是如果它是true ,那么它会。

我build议你更频繁地使用SyncContext