我在试验任务。我有过
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;
}我期望在最后一行没有死锁和崩溃,因为它不是使用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上下文,但它的工作没有问题。当我们使用ConfigureAwait()时,GetAwaiter(False)没有意义吗?
发布于 2019-03-11 11:25:26
ConfigureAwait在同一个表达式中配置await关键字的行为。它不会影响其他方法中的其他await语句,如果不使用await,则不会产生任何影响。
它控制await语句是否捕获当前的SynchronizationContext (如果有)。实际上,如果在UI线程上运行await语句,那么await task;也会在UI线程上的await之后运行代码,而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 is awaited完成时,会向线程池发送消息,线程池运行return语句。
在第二个方法中,await语句捕获当前的SynchronizationContext (它引用UI线程),并使用它在上面运行return语句。这意味着一条消息在3秒后被发送到UI线程,告诉它运行该return语句。
在第一个调用GetStringAsync的片段中
var task = GetStringAsync().ConfigureAwait(false).GetAwaiter();对ConfigureAwait的调用在这里什么也不做,因为结果不是await。你可以在没有改变的情况下移除它。
var result = task.GetResult(); // deadlock在return中运行GetStringAsync语句需要UI线程。由于在对GetResult()的调用中阻止了它,所以它无法完成GetStringAsync方法,因此出现了死锁。
在调用GetStringWithInnerCallConfigureAwaitFalseAsync的第二个片段中
var task = GetStringWithInnerCallConfigureAwaitFalseAsync().ConfigureAwait(false).GetAwaiter();同样,对ConfigureAwait(false)的调用什么也不做,因为您没有对结果进行await操作。
var result = task.GetResult(); // No deadlock这一次,GetStringWithInnerCallConfigureAwaitFalseAsync执行await ...ConfigureAwait(false),因此在线程池而不是UI线程上运行await之后的代码。因此,不需要UI线程来完成此方法,因此您可以安全地(!)堵住它。
Button11.Content = result; // No crash您在UI线程上调用了这个方法,但是您从来没有离开过它--同步调用所有东西,没有await,等等。
https://stackoverflow.com/questions/55100790
复制相似问题