阻止异步代码可能会导致死锁

阻止异步调用是一种不好的做法,因为它可能会在具有同步上下文的环境中导致死锁。最佳做法是使用 async / await一直向下。例如,以下 Windows 窗体代码导致死锁:

private async Task<bool> TryThis()
{
    Trace.TraceInformation("Starting TryThis");
    await Task.Run(() =>
    {
        Trace.TraceInformation("In TryThis task");
        for (int i = 0; i < 100; i++)
        {
            // This runs successfully - the loop runs to completion
            Trace.TraceInformation("For loop " + i);
            System.Threading.Thread.Sleep(10);
        }
    });

    // This never happens due to the deadlock
    Trace.TraceInformation("About to return");
    return true;
}

// Button click event handler
private void button1_Click(object sender, EventArgs e)
{
    // .Result causes this to block on the asynchronous call
    bool result = TryThis().Result;
    // Never actually gets here
    Trace.TraceInformation("Done with result");
}

实质上,异步调用完成后,它会等待同步上下文变为可用。但是,事件处理程序在等待 TryThis() 方法完成时保持到同步上下文,从而导致循环等待。

要解决此问题,应将代码修改为

private async void button1_Click(object sender, EventArgs e)
{
  bool result = await TryThis();
  Trace.TraceInformation("Done with result");
}

注意:事件处理程序是唯一应该使用 async void 的地方(因为你无法等待 async void 方法)。