为什么我会打扰使用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上下文中启动,并称为DownloadFileAsync
。DownloadFileAsync
也在UI上下文中启动,但是通过调用ConfigureAwait(false)
脱离了上下文。DownloadFileAsync
的其余部分在线程池上下文中运行。 但是,当DownloadFileAsync
完成,DownloadFileButton
_Click继续时,它会在UI上下文中恢复。一个好的经验法则是使用
ConfigureAwait(false)
除非你知道你确实需要上下文。
如果ConfigureAwait
初始化为false
,代码将不会在主线程(UI线程)上运行,但是如果它是true
,那么它会。
我build议你更频繁地使用SyncContext
。