我准备了WinForms应用程序来测试单行异步方法是否会导致死锁。button1_Click事件等待单行异步代理方法等待的GetZero任务.但是,它会导致死锁。为什么?我读过单行异步方法在await完成后不需要继续任何操作,因此没有委托向消息泵发送导致死锁的消息。
作为参考,button2_Click事件在没有代理调用的情况下等待任务GetZero的结果,并且应用程序可以正常工作。
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var zero = ProxyCallery().Result;
label1.Text += $"{zero}";
}
private void button2_Click(object sender, EventArgs e)
{
var zero = GetZero().Result;
label1.Text += $"{zero}";
}
private async Task<int> ProxyCallery()
{
return await GetZero();
}
private async Task<int> GetZero()
{
await Task.Delay(100).ConfigureAwait(false);
return await Task.FromResult(0);
}
}为什么button1_Click会导致死锁?
发布于 2019-07-15 16:20:39
await Task.Delay(100).ConfigureAwait(false);只为该调用配置等待。它不影响可能依赖于特定等待的等待,例如ProxyCallery()方法中的ProxyCallery()。
后一个等待仍然需要在UI线程中继续,您已经用ProxyCallery().Result阻止了这个线程。因此出现了僵局。
我读过单行异步方法在等待完成后不需要继续任何操作,因此没有委托向消息泵发送导致死锁的消息。
我不知道你在哪里读到的,但这是假的。编译器不尝试优化“尾巴等待”。实际上,即使方法中的最后一件事是await,在继续时仍然有代码要执行。至少,要打开任何异常,但也要将延续传播到由该Task方法表示的async。
因此,与方法中其他任何地方的await语句相比,总结方法的await语句在死锁潜力或异步执行的任何其他方面没有任何区别。
发布于 2019-07-15 16:21:18
您的ProxyCallery实际上是两行,也就是说在异步操作之后有一个延续:
private async Task<int> ProxyCallery()
{
var zero = await GetZero();
return zero; // <-- continuation!
}继续是返回任务的结果!
目前,上面的延续与Task.Delay任务的继续不处于相同的同步上下文中,这就是导致死锁的原因。
您创建的每个任务都应该处于相同的同步环境中!
private async Task<int> ProxyCallery()
{
var zero = await GetZero().ConfigureAwait(false);
return zero;
}https://stackoverflow.com/questions/57043455
复制相似问题