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