gpt4 book ai didi

c# - ConfigureAwait 和 GetAwaiter 改变行为

转载 作者:太空宇宙 更新时间:2023-11-03 22:36:07 25 4
gpt4 key购买 nike

我正在试验任务。我有

private async Task<string> GetStringWithInnerCallConfigureAwaitFalseAsync()
{
await Task.Delay(3000).ConfigureAwait(false);
return "Finished!";
}

private async Task<string> GetStringAsync()
{
await Task.Delay(3000);
return "Finished!";
}

我觉得奇怪的是:

private void Button10_Click(object sender, RoutedEventArgs e)
{
Button10.Content = "GetAwaiter() GetResult() + deadlock";
var task = GetStringAsync().ConfigureAwait(false).GetAwaiter();
var result = task.GetResult(); // deadlock
Button10.Content = result;
}

我预计在最后一行没有死锁崩溃是因为非 UI 上下文,因为我没有使用 GetAwaiter(),但我遇到了死锁

下一步:

private void Button11_Click(object sender, RoutedEventArgs e)
{
Button11.Content = "GetAwaiter() GetResult() No deadlock";
var task = GetStringWithInnerCallConfigureAwaitFalseAsync().ConfigureAwait(false).GetAwaiter();
var result = task.GetResult(); // No deadlock
Button11.Content = result; // No crash
}

在这里,由于非 UI 上下文,我预计最后一行会崩溃,但它可以正常工作。当我们使用 GetAwaiter() 时,ConfigureAwait(false) 没有意义吗?

最佳答案

ConfigureAwait 在同一表达式中配置 await 关键字的行为。它不影响其他方法中的其他await语句,如果不使用await则没有任何效果。

它控制await语句是否捕获当前的SynchronizationContext(如果有的话)。实际上,如果您在 UI 线程上运行 await 语句,则 await task; 将在 await< 之后 运行代码 也在 UI 线程上,而 await task.ConfigureAwait(false) 将在 ThreadPool 线程上的 await 之后运行代码。

在你的第一个例子中:

private async Task<string> GetStringWithInnerCallConfigureAwaitFalseAsync()
{
await Task.Delay(3000).ConfigureAwait(false);
return "Finished!"; // <-- Run on the thread pool
}

private async Task<string> GetStringAsync()
{
await Task.Delay(3000);
return "Finished!"; // <-- Run on the captured SynchronizationContext (if any)
}

这里的行为有所不同,那就是 return 语句在哪个线程上运行。

在第一种方法中,当 等待Task 完成时,一条消息将发送到运行 线程池>return 语句。

在第二种方法中,await 语句捕获当前的 SynchronizationContext(指的是 UI 线程),并使用它来运行 return 语句。这意味着在 3 秒过去后,一条消息将发布到 UI 线程,告诉它运行该 return 语句。


在调用 GetStringAsync 的第一个片段中:

var task = GetStringAsync().ConfigureAwait(false).GetAwaiter();

调用 ConfigureAwait 在这里什么都不做,因为您没有await结果。您可以删除它而不做任何更改。

var result = task.GetResult(); // deadlock

需要 UI 线程来运行 GetStringAsync 中的 return 语句。由于您在调用 GetResult() 时阻止了它,它无法完成 GetStringAsync 方法,因此您遇到了死锁。


在调用 GetStringWithInnerCallConfigureAwaitFalseAsync 的第二个片段中:

var task = GetStringWithInnerCallConfigureAwaitFalseAsync().ConfigureAwait(false).GetAwaiter();

同样,对 ConfigureAwait(false) 的调用没有任何作用,因为您没有等待结果。

var result = task.GetResult(); // No deadlock

这一次,GetStringWithInnerCallConfigureAwaitFalseAsync 执行 await ...ConfigureAwait(false),因此 await 之后的代码在线程上运行池而不是 UI 线程。因此,不需要 UI 线程来完成此方法,因此您可以安全地 (!) 阻止它。

Button11.Content = result; // No crash

您在 UI 线程上调用了此方法,并且您从未离开它 - 您同步调用所有内容,没有 await 等。因此您仍在 UI 线程上此时

关于c# - ConfigureAwait 和 GetAwaiter 改变行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55100790/

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