阻止异步代码可能会导致死锁
阻止异步调用是一种不好的做法,因为它可能会在具有同步上下文的环境中导致死锁。最佳做法是使用 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
方法)。