ConfigureAwait(false):当 await 等待完成时,它会尝试在线程池上下文中执行 await 之后的代码
ConfigureAwait(true):当 async 方法内的 await 执行完成时,它会尝试获取之前调用者线程所在的上下文执行方法的剩余部分
在Winform程序中没有使用ConfigureAwait(false)导致的死锁示例:
新建一个winform桌面程序,页面如下
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show($"开始运行,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "button1_Click");
Test();
MessageBox.Show($"运行结束,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "button1_Click");
}
public static void Test()
{
var task = XXXAsync(); // 开启异步任务,比如下载某个资源
var resuslt = task.Result; // 获取异步任务的结果显示给用户,这里会阻塞当前ui线程直到异步线程返回结果
MessageBox.Show($"XXXAsync运行结束显示异步任务结果:{resuslt},ThreadId:{Thread.CurrentThread.ManagedThreadId}", "Test");
}
private static async Task<string> XXXAsync()
{
await Task.Delay(1000); // 这里会导致死锁
//await Task.Delay(1000).ConfigureAwait(false); // 这样就不会死锁
MessageBox.Show($"XXXAsync运行结束,ThreadId:{Thread.CurrentThread.ManagedThreadId}", "XXXAsync");
return "XXXAsync.Result";
}
这样运行会发生代码死锁.
这是由于 调用 var task = XXXAsync(); 时候异步线程执行的操作,
var resuslt = task.Result; 当等待结果的时候,处理排队回调的线程却还被你阻塞着等待操作完成,
这是就算 XXXAsync() 执行完成时,将结果返回不到主线程(因为主线程阻塞等待),主线程已经卡死,就会造成死锁的状态.
如果加 Task.Delay(1000).ConfigureAwait(false) 就不会造成死锁,它就不会将回调排队送回原始上下文,进而避免了死锁。