阻止非同步程式碼可能會導致死鎖

阻止非同步呼叫是一種不好的做法,因為它可能會在具有同步上下文的環境中導致死鎖。最佳做法是使用 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 方法)。