如何在使用async/await时修复Win Forms构造函数中的死锁

本文关键字:Forms Win 构造函数 死锁 async await | 更新日期: 2023-09-27 18:26:42

这是我的最小repo情况:

public Form1()
{
    Task.Delay(100).Wait();  // Works just fine
    this.Await().Wait();     // Blocks indefinitely
}
private async Task Await()
{
    await Task.Delay(100);
}

这是怎么回事?为什么这两个人的行为不同?我该怎么做才能使后一个有效?

我的实际案例不那么琐碎,我不能"只使用第一个选项"。

如何在使用async/await时修复Win Forms构造函数中的死锁

您看到了一个经典的死锁情况,我在博客和MSDN文章中对此进行了描述。简而言之,在await完成后,async方法正试图在UI线程上恢复,而您已通过调用Wait阻止了该线程。

要修复它,理想情况下,您希望一直使用async(即,永远不要阻塞async代码)。构造函数在这里造成了困难(因为它们不能是async);我在博客上探索了几个选项。正确的选项取决于您的代码库,但如果可能的话,我建议使用async工厂方法。选项包括:

  • 异步工厂方法
  • 异步延迟初始化
  • 异步初始化模式

如果你绝对不能使用我在博客上描述的任何一个选项,那么你可以在所有的async方法中使用ConfigureAwait(false)来解决这个问题,这样你的Wait()就不会死锁。然而,这个将在异步方法调用期间阻塞UI线程(这有点违背了它们最初作为async的目的…)