斯蒂芬克利里有一个非常好的系列,你可以在这里找到,我引用了针对你的问题的文章:
大多数时候,您不需要同步回“主”上下文。大多数异步方法在设计时都会考虑到组合:它们等待其他操作,每个操作都代表一个异步操作本身(可以由其他操作组合)。在这种情况下,您想通过调用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)
,除非你知道你确实需要上下文。