我想先把代码放一下,然后解释一下情况并根据这个问题提出我的问题:
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private async void Button_Click_2(object sender, RoutedEventArgs e) {
var result = await GetValuesAsync();
Foo.Text += result;
}
public async Task<string> GetValuesAsync() {
using (var httpClient = new HttpClient()) {
var response = await httpClient
.GetAsync("http://www.google.com")
.ConfigureAwait(continueOnCapturedContext: false);
// This is the continuation for the httpClient.GetAsync method.
// We shouldn't get back to sync context here
// Cuz the continueOnCapturedContext is set to *false*
// for the Task which is returned from httpClient.GetAsync method
var html = await GetStringAsync();
// This is the continuation for the GetStringAsync method.
// Should I get back to sync context here?
// Cuz the continueOnCapturedContext is set to *true*
// for the Task which is returned from GetStringAsync
// However, GetStringAsync may be executed in another thread
// which has no knowledge for the sync context
// because the continueOnCapturedContext is set to *false*
// for the Task which is returned from httpClient.GetAsync method.
// But, on the other hand, GetStringAsync method also has a
// chance to be executed in the UI thread but we shouldn't be
// relying on that.
html += "Hey...";
Foo.Text = html;
return html;
}
}
public async Task<string> GetStringAsync() {
await Task.Delay(1000);
return "Done...";
}
}
这是一个相当简单的WPF示例,它运行在.NET 4.5上,可能没有多大意义,但这可以帮助我解释我的情况。
我在屏幕上有一个按钮,它有一个异步点击事件。当你看着 GetValuesAsync
代码,你会看到的用法 await
关键字两次。第一次使用,我设置 continueOnCapturedContext
的参数 Task.ConfigureAwait
方法 false
。所以,这表明我 不一定要 我继续在里面执行 SynchronizationContext.Current
。到现在为止还挺好。
在第二个 await
用法(用 GetStringAsync
方法),我没有打电话给 ConfigureAwait
方法。所以,我基本上表明了我 想 回到当前的同步上下文继续 GetStringAsync
方法。所以,正如你所看到的,我试着设置 TextBlock.Text
(继承者内部属于UI线程)属性。
当我运行应用程序并单击按钮时,我得到一个异常,给我以下消息:
调用线程无法访问此对象,因为它不同 线程拥有它。
起初,这对我没有任何意义,我认为我发现了一个错误,但后来,我意识到了这一点 GetStringAsync
可能在另一个线程(很有可能)中执行,该线程与UI线程不同,并且不知道同步上下文,因为 continueOnCapturedContext
被设定为 false
为了 Task
从...返回 httpClient.GetAsync
方法。
这是这种情况吗?此外,在这种情况下,是否有机会 GetStringAsync
要回发到UI线程的方法,可以在UI线程内执行httpClient.GetAsync方法延续吗?
我在代码中也有一些注释。鉴于我的问题和代码中的注释,我在这里遗漏了什么吗?