tug*_*erk 11 c# asynchronous synchronizationcontext task-parallel-library async-await
我想先把代码放在一边,然后解释一下情况并根据这个问题提出我的问题:
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...";
}
}
Run Code Online (Sandbox Code Playgroud)
这是一个相当简单的WPF示例,它运行在.NET 4.5上,可能没有多大意义,但这可以帮助我解释我的情况.
我在屏幕上有一个按钮,它有一个异步点击事件.查看GetValuesAsync代码时,您将看到await关键字的使用两次.在第一次使用时,我将方法的continueOnCapturedContext参数设置Task.ConfigureAwait为false.所以,这表明我不一定希望我的继续在内部执行SynchronizationContext.Current.到现在为止还挺好.
在第二次await使用(使用GetStringAsync方法)时,我没有调用该ConfigureAwait方法.所以,我基本上表示我想回到当前的同步上下文继续该GetStringAsync方法.所以,正如你所看到的,我尝试TextBlock.Text在continuation中设置(属于UI线程)属性.
当我运行应用程序并单击按钮时,我得到一个异常,给我以下消息:
调用线程无法访问此对象,因为另一个线程拥有它.
起初,这对我没有任何意义,我认为我发现了一个错误,但后来,我意识到GetStringAsync可能会在另一个线程(很可能)中执行,这个线程与UI线程不同,并且不知道同步上下文,因为continueOnCapturedContext设置false为Task从httpClient.GetAsync方法返回的.
这是这种情况吗?此外,在这种情况下,是否有机GetStringAsync会将方法发回UI线程,可以在UI线程内执行httpClient.GetAsync方法延续?
我在代码中也有一些注释.鉴于我的问题和代码中的注释,我在这里遗漏了什么吗?
Ste*_*ary 11
当你调用ConfigureAwait(false),该方法的其余部分将在一个线程池线程执行,除非在Task你await荷兰国际集团已经完成.
因为GetAsync几乎肯定会以异步方式运行,所以我希望GetStringAsync在线程池线程上运行.
public async Task<string> GetValuesAsync() {
using (var httpClient = new HttpClient()) {
var response = await httpClient
.GetAsync("http://www.google.com")
.ConfigureAwait(continueOnCapturedContext: false);
// And now we're on the thread pool thread.
// This "await" will capture the current SynchronizationContext...
var html = await GetStringAsync();
// ... and resume it here.
// But it's not the UI SynchronizationContext.
// It's the ThreadPool SynchronizationContext.
// So we're back on a thread pool thread here.
// So this will raise an exception.
html += "Hey...";
Foo.Text = html;
return html;
}
}
Run Code Online (Sandbox Code Playgroud)
此外,在这种情况下,是否有机会将GetStringAsync方法发布回UI线程,可以在UI线程内执行httpClient.GetAsync方法延续?
GetStringAsync在UI线程上运行的唯一方法是GetAsync在实际await编辑之前完成.极不可能.
出于这个原因,我更喜欢使用ConfigureAwait(false)的每 await一次上下文不再需要.
| 归档时间: |
|
| 查看次数: |
6634 次 |
| 最近记录: |