gpt4 book ai didi

c# - async/await 与 ConfigureAwait 的 continueOnCapturedContext 参数和用于异步延续的 SynchronizationContext

转载 作者:可可西里 更新时间:2023-11-01 08:44:24 26 4
gpt4 key购买 nike

我想先放代码,然后说明情况,并据此提出我的问题:

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 关键字的用法两次。第一次使用时,我将 Task.ConfigureAwait 方法的 continueOnCapturedContext 参数设置为 false。因此,这表明我不一定希望我的延续在SynchronizationContext.Current 中执行。到目前为止一切顺利。

在第二次使用 await 时(使用 GetStringAsync 方法),我没有调用 ConfigureAwait 方法。因此,我基本上表示我想要返回到当前同步上下文以继续GetStringAsync 方法。因此,如您所见,我尝试在延续内设置 TextBlock.Text(属于 UI 线程)属性。

当我运行应用程序并单击按钮时,出现异常并显示以下消息:

The calling thread cannot access this object because a different thread owns it.

起初,这对我来说毫无意义,我认为我发现了一个错误,但后来,我意识到 GetStringAsync 可能在与 UI 不同的另一个线程中执行(很有可能)线程并且不知道同步上下文,因为对于从 httpClient.GetAsync 返回的 TaskcontinueOnCapturedContext 设置为 false 方法。

这里是这样吗?此外,在这种情况下,是否有可能将 GetStringAsync 方法回发到 UI 线程,因为 httpClient.GetAsync 方法继续可能在 UI 线程内执行?

我在代码中也有一些注释。鉴于我的问题和代码中的注释,我是否遗漏了什么?

最佳答案

当您调用 ConfigureAwait(false) 时,该方法的其余部分将在线程池线程上执行,除非您的Task重新 awaiting 已经完成。

由于 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;
}
}

Also, in this case, is there a chance for GetStringAsync method to be posted back to UI thread bacuse the httpClient.GetAsync method continuation may be executed inside the UI thread?

GetStringAsync 在 UI 线程上运行的唯一方法是 GetAsync 在它实际被 await 编辑之前完成。 不太可能。

出于这个原因,我更喜欢在不再需要上下文时对每个 await 使用ConfigureAwait(false)

关于c# - async/await 与 ConfigureAwait 的 continueOnCapturedContext 参数和用于异步延续的 SynchronizationContext,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12933090/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com